mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 87e8abdf10ff5c2068354690817dd32a86d613c2 Former-commit-id: 9eeb9dd07422fded5300087200f781d7d7064b50 Former-commit-id: a35e9e5e97952e268bcb3310194d738282817052pull/1/head
26 changed files with 882 additions and 19 deletions
@ -0,0 +1,91 @@ |
|||
// <copyright file="Vector4Extensions.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Vector4"/> struct.
|
|||
/// </summary>
|
|||
public static class Vector4Extensions |
|||
{ |
|||
/// <summary>
|
|||
/// Compresses a linear color signal to its sRGB equivalent.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="linear">The <see cref="Vector4"/> whose signal to compress.</param>
|
|||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|||
public static Vector4 Compress(this Vector4 linear) |
|||
{ |
|||
// TODO: Is there a faster way to do this?
|
|||
float r = Compress(linear.X); |
|||
float g = Compress(linear.Y); |
|||
float b = Compress(linear.Z); |
|||
|
|||
return new Vector4(r, g, b, linear.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands an sRGB color signal to its linear equivalent.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="gamma">The <see cref="Color"/> whose signal to expand.</param>
|
|||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|||
public static Vector4 Expand(this Vector4 gamma) |
|||
{ |
|||
// TODO: Is there a faster way to do this?
|
|||
float r = Expand(gamma.X); |
|||
float g = Expand(gamma.Y); |
|||
float b = Expand(gamma.Z); |
|||
|
|||
return new Vector4(r, g, b, gamma.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the compressed sRGB value from an linear signal.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="signal">The signal value to compress.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float Compress(float signal) |
|||
{ |
|||
if (signal <= 0.0031308f) |
|||
{ |
|||
return signal * 12.92f; |
|||
} |
|||
|
|||
return (1.055f * (float)Math.Pow(signal, 0.41666666f)) - 0.055f; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the expanded linear value from an sRGB signal.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="signal">The signal value to expand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float Expand(float signal) |
|||
{ |
|||
if (signal <= 0.04045f) |
|||
{ |
|||
return signal / 12.92f; |
|||
} |
|||
|
|||
return (float)Math.Pow((signal + 0.055f) / 1.055f, 2.4f); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
// <copyright file="Lomograph.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
using Processors; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{T,TP}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Lomograph camera effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
|
|||
public static Image<T, TP> Lomograph<T, TP>(this Image<T, TP> source, ProgressEventHandler progressHandler = null) |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
return Lomograph(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Lomograph camera effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="rectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|||
/// </param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
|
|||
public static Image<T, TP> Lomograph<T, TP>(this Image<T, TP> source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
LomographProcessor<T, TP> processor = new LomographProcessor<T, TP>(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// <copyright file="GreyscaleMode.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Provides enumeration over the various greyscale methods available.
|
|||
/// </summary>
|
|||
public enum GreyscaleMode |
|||
{ |
|||
/// <summary>
|
|||
/// ITU-R Recommendation BT.709
|
|||
/// </summary>
|
|||
Bt709, |
|||
|
|||
/// <summary>
|
|||
/// ITU-R Recommendation BT.601
|
|||
/// </summary>
|
|||
Bt601 |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
// <copyright file="Polaroid.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
using Processors; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{T,TP}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Polaroid camera effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
|
|||
public static Image<T, TP> Polaroid<T, TP>(this Image<T, TP> source, ProgressEventHandler progressHandler = null) |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
return Polaroid(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Polaroid camera effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="rectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|||
/// </param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
|
|||
public static Image<T, TP> Polaroid<T, TP>(this Image<T, TP> source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
PolaroidProcessor<T, TP> processor = new PolaroidProcessor<T, TP>(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// <copyright file="BlackWhiteProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Converts the colors of the image to their black and white equivalent.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class BlackWhiteProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 1.5f, |
|||
M12 = 1.5f, |
|||
M13 = 1.5f, |
|||
M21 = 1.5f, |
|||
M22 = 1.5f, |
|||
M23 = 1.5f, |
|||
M31 = 1.5f, |
|||
M32 = 1.5f, |
|||
M33 = 1.5f, |
|||
M41 = -1f, |
|||
M42 = -1f, |
|||
M43 = -1f, |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
// <copyright file="GreyscaleBt601Processor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Converts the colors of the image to greyscale applying the formula as specified by
|
|||
/// ITU-R Recommendation BT.601 <see href="https://en.wikipedia.org/wiki/Luma_%28video%29#Rec._601_luma_versus_Rec._709_luma_coefficients"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class GreyscaleBt601Processor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = .299f, |
|||
M12 = .299f, |
|||
M13 = .299f, |
|||
M21 = .587f, |
|||
M22 = .587f, |
|||
M23 = .587f, |
|||
M31 = .114f, |
|||
M32 = .114f, |
|||
M33 = .114f |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
// <copyright file="HueProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// An <see cref="IImageProcessor"/> to change the hue of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class HueProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <summary>
|
|||
/// The <see cref="Matrix4x4"/> used to alter the image.
|
|||
/// </summary>
|
|||
private Matrix4x4 matrix; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HueProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="angle">The new brightness of the image. Must be between -100 and 100.</param>
|
|||
public HueProcessor(float angle) |
|||
{ |
|||
// Wrap the angle round at 360.
|
|||
angle = angle % 360; |
|||
|
|||
// Make sure it's not negative.
|
|||
while (angle < 0) |
|||
{ |
|||
angle += 360; |
|||
} |
|||
|
|||
this.Angle = angle; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the rotation value.
|
|||
/// </summary>
|
|||
public float Angle { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => this.matrix; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
float radians = (float)ImageMaths.DegreesToRadians(this.Angle); |
|||
double cosradians = Math.Cos(radians); |
|||
double sinradians = Math.Sin(radians); |
|||
|
|||
float lumR = .213f; |
|||
float lumG = .715f; |
|||
float lumB = .072f; |
|||
|
|||
float oneMinusLumR = 1 - lumR; |
|||
float oneMinusLumG = 1 - lumG; |
|||
float oneMinusLumB = 1 - lumB; |
|||
|
|||
// The matrix is set up to preserve the luminance of the image.
|
|||
// See http://graficaobscura.com/matrix/index.html
|
|||
// Number are taken from https://msdn.microsoft.com/en-us/library/jj192162(v=vs.85).aspx
|
|||
Matrix4x4 matrix4X4 = new Matrix4x4() |
|||
{ |
|||
M11 = (float)(lumR + (cosradians * oneMinusLumR) - (sinradians * lumR)), |
|||
M12 = (float)(lumR - (cosradians * lumR) - (sinradians * 0.143)), |
|||
M13 = (float)(lumR - (cosradians * lumR) - (sinradians * oneMinusLumR)), |
|||
M21 = (float)(lumG - (cosradians * lumG) - (sinradians * lumG)), |
|||
M22 = (float)(lumG + (cosradians * oneMinusLumG) + (sinradians * 0.140)), |
|||
M23 = (float)(lumG - (cosradians * lumG) + (sinradians * lumG)), |
|||
M31 = (float)(lumB - (cosradians * lumB) + (sinradians * oneMinusLumB)), |
|||
M32 = (float)(lumB - (cosradians * lumB) - (sinradians * 0.283)), |
|||
M33 = (float)(lumB + (cosradians * oneMinusLumB) + (sinradians * lumB)) |
|||
}; |
|||
|
|||
this.matrix = matrix4X4; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// <copyright file="KodachromeProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating an old Kodachrome camera effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class KodachromeProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.6997023f, |
|||
M22 = 0.4609577f, |
|||
M33 = 0.397218f, |
|||
M41 = 0.005f, |
|||
M42 = -0.005f, |
|||
M43 = 0.005f |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// <copyright file="LomographProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating an old Lomograph effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class LomographProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 1.5f, |
|||
M22 = 1.45f, |
|||
M33 = 1.11f, |
|||
M41 = -.1f, |
|||
M42 = .0f, |
|||
M43 = -.08f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void AfterApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
T packed = default(T); |
|||
packed.PackBytes(0, 10, 0, 255); |
|||
new VignetteProcessor<T, TP> { VignetteColor = packed }.Apply(target, target, targetRectangle); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
// <copyright file="PolaroidProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating an old Polaroid effect.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class PolaroidProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 1.538f, |
|||
M12 = -0.062f, |
|||
M13 = -0.262f, |
|||
M21 = -0.022f, |
|||
M22 = 1.578f, |
|||
M23 = -0.022f, |
|||
M31 = .216f, |
|||
M32 = -.16f, |
|||
M33 = 1.5831f, |
|||
M41 = 0.02f, |
|||
M42 = -0.05f, |
|||
M43 = -0.05f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void AfterApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
T packedV = default(T); |
|||
packedV.PackBytes(102, 34, 0, 255); |
|||
new VignetteProcessor<T, TP> { VignetteColor = packedV }.Apply(target, target, targetRectangle); |
|||
|
|||
T packedG = default(T); |
|||
packedG.PackBytes(255, 153, 102, 178); |
|||
new GlowProcessor<T, TP> |
|||
{ |
|||
GlowColor = packedG, |
|||
RadiusX = target.Width / 4f, |
|||
RadiusY = target.Width / 4f |
|||
} |
|||
.Apply(target, target, targetRectangle); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
// <copyright file="SaturationProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// An <see cref="IImageProcessor"/> to change the saturation of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class SaturationProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <summary>
|
|||
/// The saturation to be applied to the image.
|
|||
/// </summary>
|
|||
private readonly int saturation; |
|||
|
|||
/// <summary>
|
|||
/// The <see cref="Matrix4x4"/> used to alter the image.
|
|||
/// </summary>
|
|||
private Matrix4x4 matrix; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="SaturationProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="saturation">The new saturation of the image. Must be between -100 and 100.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="saturation"/> is less than -100 or is greater than 100.
|
|||
/// </exception>
|
|||
public SaturationProcessor(int saturation) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(saturation, -100, 100, nameof(saturation)); |
|||
this.saturation = saturation; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => this.matrix; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
float saturationFactor = this.saturation / 100f; |
|||
|
|||
// Stop at -1 to prevent inversion.
|
|||
saturationFactor++; |
|||
|
|||
// The matrix is set up to "shear" the colour space using the following set of values.
|
|||
// Note that each colour component has an effective luminance which contributes to the
|
|||
// overall brightness of the pixel.
|
|||
// See http://graficaobscura.com/matrix/index.html
|
|||
float saturationComplement = 1.0f - saturationFactor; |
|||
float saturationComplementR = 0.3086f * saturationComplement; |
|||
float saturationComplementG = 0.6094f * saturationComplement; |
|||
float saturationComplementB = 0.0820f * saturationComplement; |
|||
|
|||
Matrix4x4 matrix4X4 = new Matrix4x4() |
|||
{ |
|||
M11 = saturationComplementR + saturationFactor, |
|||
M12 = saturationComplementR, |
|||
M13 = saturationComplementR, |
|||
M21 = saturationComplementG, |
|||
M22 = saturationComplementG + saturationFactor, |
|||
M23 = saturationComplementG, |
|||
M31 = saturationComplementB, |
|||
M32 = saturationComplementB, |
|||
M33 = saturationComplementB + saturationFactor, |
|||
}; |
|||
|
|||
this.matrix = matrix4X4; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
// <copyright file="SepiaProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Converts the colors of the image to their sepia equivalent.
|
|||
/// The formula used matches the svg specification. <see href="http://www.w3.org/TR/filter-effects/#sepiaEquivalent"/>
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class SepiaProcessor<T, TP> : ColorMatrixFilter<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = .393f, |
|||
M12 = .349f, |
|||
M13 = .272f, |
|||
M21 = .769f, |
|||
M22 = .686f, |
|||
M23 = .534f, |
|||
M31 = .189f, |
|||
M32 = .168f, |
|||
M33 = .131f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
// <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 ImageProcessorCore.Processors |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Creates a glow effect on the image
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class GlowProcessor<T, TP> : ImageProcessor<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GlowProcessor"/> class.
|
|||
/// </summary>
|
|||
public GlowProcessor() |
|||
{ |
|||
this.GlowColor.PackVector(Color.White.ToVector4()); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the glow color to apply.
|
|||
/// </summary>
|
|||
public T GlowColor { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the the x-radius.
|
|||
/// </summary>
|
|||
public float RadiusX { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the the y-radius.
|
|||
/// </summary>
|
|||
public float RadiusY { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
T glowColor = this.GlowColor; |
|||
Vector2 centre = Rectangle.Center(targetRectangle).ToVector2(); |
|||
float rX = this.RadiusX > 0 ? this.RadiusX : targetRectangle.Width / 2f; |
|||
float rY = this.RadiusY > 0 ? this.RadiusY : targetRectangle.Height / 2f; |
|||
float maxDistance = (float)Math.Sqrt(rX * rX + rY * rY); |
|||
|
|||
using (IPixelAccessor<T, TP> sourcePixels = source.Lock()) |
|||
using (IPixelAccessor<T, TP> targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
// TODO: Premultiply?
|
|||
float distance = Vector2.Distance(centre, new Vector2(x, y)); |
|||
Vector4 sourceColor = sourcePixels[x, y].ToVector4(); |
|||
Vector4 result = Vector4.Lerp(glowColor.ToVector4(), sourceColor, .5f * (distance / maxDistance)); |
|||
T packed = default(T); |
|||
packed.PackVector(result); |
|||
targetPixels[x, y] = packed; |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,79 @@ |
|||
// <copyright file="VignetteProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Processors |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Creates a vignette effect on the image
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The pixel format.</typeparam>
|
|||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|||
public class VignetteProcessor<T, TP> : ImageProcessor<T, TP> |
|||
where T : IPackedVector<TP> |
|||
where TP : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="VignetteProcessor"/> class.
|
|||
/// </summary>
|
|||
public VignetteProcessor() |
|||
{ |
|||
this.VignetteColor.PackVector(Color.Black.ToVector4()); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the vignette color to apply.
|
|||
/// </summary>
|
|||
public T VignetteColor { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the the x-radius.
|
|||
/// </summary>
|
|||
public float RadiusX { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the the y-radius.
|
|||
/// </summary>
|
|||
public float RadiusY { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
T vignetteColor = this.VignetteColor; |
|||
Vector2 centre = Rectangle.Center(targetRectangle).ToVector2(); |
|||
float rX = this.RadiusX > 0 ? this.RadiusX : targetRectangle.Width / 2f; |
|||
float rY = this.RadiusY > 0 ? this.RadiusY : targetRectangle.Height / 2f; |
|||
float maxDistance = (float)Math.Sqrt(rX * rX + rY * rY); |
|||
|
|||
using (IPixelAccessor<T, TP> sourcePixels = source.Lock()) |
|||
using (IPixelAccessor<T, TP> targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
float distance = Vector2.Distance(centre, new Vector2(x, y)); |
|||
Vector4 sourceColor = sourcePixels[x, y].ToVector4(); |
|||
Vector4 result = Vector4.Lerp(vignetteColor.ToVector4(), sourceColor, 1 - .9f * (distance / maxDistance)); |
|||
T packed = default(T); |
|||
packed.PackVector(result); |
|||
targetPixels[x, y] = packed; |
|||
|
|||
} |
|||
this.OnRowProcessed(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,38 @@ |
|||
// <copyright file="LomographTest.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Tests |
|||
{ |
|||
using System.IO; |
|||
|
|||
using Xunit; |
|||
|
|||
public class LomographTest : FileTestBase |
|||
{ |
|||
[Fact] |
|||
public void ImageShouldApplyLomographFilter() |
|||
{ |
|||
const string path = "TestOutput/Lomograph"; |
|||
if (!Directory.Exists(path)) |
|||
{ |
|||
Directory.CreateDirectory(path); |
|||
} |
|||
|
|||
foreach (string file in Files) |
|||
{ |
|||
using (FileStream stream = File.OpenRead(file)) |
|||
{ |
|||
string filename = Path.GetFileName(file); |
|||
Image image = new Image(stream); |
|||
using (FileStream output = File.OpenWrite($"{path}/{filename}")) |
|||
{ |
|||
image.Lomograph() |
|||
.Save(output); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// <copyright file="PolaroidTest.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Tests |
|||
{ |
|||
using System.IO; |
|||
|
|||
using Xunit; |
|||
|
|||
public class PolaroidTest : FileTestBase |
|||
{ |
|||
[Fact] |
|||
public void ImageShouldApplyPolaroidFilter() |
|||
{ |
|||
const string path = "TestOutput/Polaroid"; |
|||
if (!Directory.Exists(path)) |
|||
{ |
|||
Directory.CreateDirectory(path); |
|||
} |
|||
|
|||
foreach (string file in Files) |
|||
{ |
|||
using (FileStream stream = File.OpenRead(file)) |
|||
{ |
|||
string filename = Path.GetFileName(file); |
|||
Image image = new Image(stream); |
|||
using (FileStream output = File.OpenWrite($"{path}/{filename}")) |
|||
{ |
|||
image.Polaroid() |
|||
.Save(output); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue