mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: c1c2d867171de871262331e5db1e55f0fe462312 Former-commit-id: 41d014fd7ba8e3a7f8a84d40d368eb330baab3c5 Former-commit-id: 78ac6e4c0afaeefd95f3604bf778584b48c3caddaf/merge-core
222 changed files with 0 additions and 23781 deletions
@ -1,124 +0,0 @@ |
|||
// <copyright file="Bootstrapper.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.Collections.Generic; |
|||
using System.Collections.ObjectModel; |
|||
using System.Text; |
|||
|
|||
using ImageProcessorCore.Formats; |
|||
|
|||
/// <summary>
|
|||
/// Provides initialization code which allows extending the library.
|
|||
/// </summary>
|
|||
public class Bootstrapper |
|||
{ |
|||
/// <summary>
|
|||
/// A new instance Initializes a new instance of the <see cref="Bootstrapper"/> class.
|
|||
/// with lazy initialization.
|
|||
/// </summary>
|
|||
private static readonly Lazy<Bootstrapper> Lazy = new Lazy<Bootstrapper>(() => new Bootstrapper()); |
|||
|
|||
/// <summary>
|
|||
/// The default list of supported <see cref="IImageFormat"/>
|
|||
/// </summary>
|
|||
private readonly List<IImageFormat> imageFormats; |
|||
|
|||
private readonly Dictionary<Type, Type> pixelAccessors; |
|||
|
|||
/// <summary>
|
|||
/// Prevents a default instance of the <see cref="Bootstrapper"/> class from being created.
|
|||
/// </summary>
|
|||
private Bootstrapper() |
|||
{ |
|||
this.imageFormats = new List<IImageFormat> |
|||
{ |
|||
new BmpFormat(), |
|||
new JpegFormat(), |
|||
new PngFormat(), |
|||
new GifFormat() |
|||
}; |
|||
|
|||
this.pixelAccessors = new Dictionary<Type, Type> |
|||
{ |
|||
{ typeof(Bgra32), typeof(Bgra32PixelAccessor) } |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current bootstrapper instance.
|
|||
/// </summary>
|
|||
public static Bootstrapper Instance = Lazy.Value; |
|||
|
|||
/// <summary>
|
|||
/// Gets the list of supported <see cref="IImageFormat"/>
|
|||
/// </summary>
|
|||
public IReadOnlyCollection<IImageFormat> ImageFormats => new ReadOnlyCollection<IImageFormat>(this.imageFormats); |
|||
|
|||
/// <summary>
|
|||
/// Adds a new <see cref="IImageFormat"/> to the collection of supported image formats.
|
|||
/// </summary>
|
|||
/// <param name="format">The new format to add.</param>
|
|||
public void AddImageFormat(IImageFormat format) |
|||
{ |
|||
this.imageFormats.Add(format); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an instance of the correct <see cref="IPixelAccessor"/> for the packed vector.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixel data.</typeparam>
|
|||
/// <param name="image">The image</param>
|
|||
/// <returns>The <see cref="IPixelAccessor"/></returns>
|
|||
public IPixelAccessor GetPixelAccessor<TPackedVector>(Image<TPackedVector> image) |
|||
where TPackedVector : IPackedVector |
|||
{ |
|||
Type packed = typeof(TPackedVector); |
|||
if (!this.pixelAccessors.ContainsKey(packed)) |
|||
{ |
|||
// TODO: Double check this. It should work...
|
|||
return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image); |
|||
} |
|||
|
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
stringBuilder.AppendLine("PixelAccessor cannot be loaded. Available accessors:"); |
|||
|
|||
foreach (Type value in this.pixelAccessors.Values) |
|||
{ |
|||
stringBuilder.AppendLine("-" + value.Name); |
|||
} |
|||
|
|||
throw new NotSupportedException(stringBuilder.ToString()); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an instance of the correct <see cref="IPixelAccessor"/> for the packed vector.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixel data.</typeparam>
|
|||
/// <param name="image">The image</param>
|
|||
/// <returns>The <see cref="IPixelAccessor"/></returns>
|
|||
public IPixelAccessor GetPixelAccessor<TPackedVector>(ImageFrame<TPackedVector> image) |
|||
where TPackedVector : IPackedVector |
|||
{ |
|||
Type packed = typeof(TPackedVector); |
|||
if (!this.pixelAccessors.ContainsKey(packed)) |
|||
{ |
|||
return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image); |
|||
} |
|||
|
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
stringBuilder.AppendLine("PixelAccessor cannot be loaded. Available accessors:"); |
|||
|
|||
foreach (Type value in this.pixelAccessors.Values) |
|||
{ |
|||
stringBuilder.AppendLine("-" + value.Name); |
|||
} |
|||
|
|||
throw new NotSupportedException(stringBuilder.ToString()); |
|||
} |
|||
} |
|||
} |
|||
@ -1,518 +0,0 @@ |
|||
// <copyright file="Color.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.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Represents a four-component color using red, green, blue, and alpha data.
|
|||
/// Each component is stored in premultiplied format multiplied by the alpha component.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public partial struct Color : IEquatable<Color>, IAlmostEquatable<Color, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents an empty <see cref="Color"/> that has R, G, B, and A values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Color Empty = default(Color); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector4 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component of this <see cref="Color"/>.</param>
|
|||
/// <param name="g">The green component of this <see cref="Color"/>.</param>
|
|||
/// <param name="b">The blue component of this <see cref="Color"/>.</param>
|
|||
/// <param name="a">The alpha component of this <see cref="Color"/>.</param>
|
|||
public Color(float r, float g, float b, float a = 1) |
|||
: this() |
|||
{ |
|||
this.backingVector = new Vector4(r, g, b, a); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="hex">
|
|||
/// The hexadecimal representation of the combined color components arranged
|
|||
/// in rgb, rrggbb, or aarrggbb format to match web syntax.
|
|||
/// </param>
|
|||
public Color(string hex) |
|||
: this() |
|||
{ |
|||
// Hexadecimal representations are layed out AARRGGBB to we need to do some reordering.
|
|||
hex = hex.StartsWith("#") ? hex.Substring(1) : hex; |
|||
|
|||
if (hex.Length != 8 && hex.Length != 6 && hex.Length != 3) |
|||
{ |
|||
throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); |
|||
} |
|||
|
|||
if (hex.Length == 8) |
|||
{ |
|||
float r = Convert.ToByte(hex.Substring(2, 2), 16); |
|||
float g = Convert.ToByte(hex.Substring(4, 2), 16); |
|||
float b = Convert.ToByte(hex.Substring(6, 2), 16); |
|||
float a = Convert.ToByte(hex.Substring(0, 2), 16); |
|||
|
|||
// Do division of Vector4 instead of each component to utilize SIMD optimizations
|
|||
this.backingVector = new Vector4(r, g, b, a) / 255f; |
|||
this.backingVector = FromNonPremultiplied(this.backingVector, this.A); |
|||
|
|||
} |
|||
else if (hex.Length == 6) |
|||
{ |
|||
float r = Convert.ToByte(hex.Substring(0, 2), 16); |
|||
float g = Convert.ToByte(hex.Substring(2, 2), 16); |
|||
float b = Convert.ToByte(hex.Substring(4, 2), 16); |
|||
float a = 255f; |
|||
|
|||
// Do division of Vector4 instead of each component to utilize SIMD optimizations
|
|||
this.backingVector = new Vector4(r, g, b, a) / 255f; |
|||
} |
|||
else |
|||
{ |
|||
string rh = char.ToString(hex[0]); |
|||
string gh = char.ToString(hex[1]); |
|||
string bh = char.ToString(hex[2]); |
|||
|
|||
float r = Convert.ToByte(rh + rh, 16); |
|||
float g = Convert.ToByte(gh + gh, 16); |
|||
float b = Convert.ToByte(bh + bh, 16); |
|||
float a = 255f; |
|||
|
|||
this.backingVector = new Vector4(r, g, b, a) / 255f; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
public Color(Vector4 vector) |
|||
{ |
|||
this.backingVector = vector; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector representing the red, green, and blue componenets.
|
|||
/// </param>
|
|||
public Color(Vector3 vector) |
|||
{ |
|||
this.backingVector = new Vector4(vector, 1); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector representing the red, green, and blue componenets.
|
|||
/// </param>
|
|||
/// <param name="alpha">The alpha component.</param>
|
|||
public Color(Vector3 vector, float alpha) |
|||
{ |
|||
this.backingVector = new Vector4(vector, alpha); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the red component of the color.
|
|||
/// </summary>
|
|||
public float R |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.X; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.X = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the green component of the color.
|
|||
/// </summary>
|
|||
public float G |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.Y; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.Y = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the blue component of the color.
|
|||
/// </summary>
|
|||
public float B |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.Z; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.Z = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the alpha component of the color.
|
|||
/// </summary>
|
|||
public float A |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.W; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.W = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Color"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Gets this color with the component values clamped from 0 to 1.
|
|||
/// </summary>
|
|||
public Color Limited => new Color(Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One)); |
|||
|
|||
/// <summary>
|
|||
/// Computes the product of multiplying a color by a given factor.
|
|||
/// </summary>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <param name="factor">The multiplication factor.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator *(Color color, float factor) |
|||
{ |
|||
return new Color(color.backingVector * factor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the product of multiplying a color by a given factor.
|
|||
/// </summary>
|
|||
/// <param name="factor">The multiplication factor.</param>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator *(float factor, Color color) |
|||
{ |
|||
return new Color(color.backingVector * factor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the product of multiplying two colors.
|
|||
/// </summary>
|
|||
/// <param name="left">The color on the left hand of the operand.</param>
|
|||
/// <param name="right">The color on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator *(Color left, Color right) |
|||
{ |
|||
return new Color(left.backingVector * right.backingVector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the sum of adding two colors.
|
|||
/// </summary>
|
|||
/// <param name="left">The color on the left hand of the operand.</param>
|
|||
/// <param name="right">The color on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator +(Color left, Color right) |
|||
{ |
|||
return new Color(left.backingVector + right.backingVector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the difference left by subtracting one color from another.
|
|||
/// </summary>
|
|||
/// <param name="left">The color on the left hand of the operand.</param>
|
|||
/// <param name="right">The color on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator -(Color left, Color right) |
|||
{ |
|||
return new Color(left.backingVector - right.backingVector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Color"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Color"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Color"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Color left, Color right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Color"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Color"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Color"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Color left, Color right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a new color whose components are the average of the components of first and second.
|
|||
/// </summary>
|
|||
/// <param name="first">The first color.</param>
|
|||
/// <param name="second">The second color.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Color Average(Color first, Color second) |
|||
{ |
|||
return new Color((first.backingVector + second.backingVector) * .5f); |
|||
} |
|||
|
|||
/// <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="Color"/> whose signal to compress.</param>
|
|||
/// <returns>The <see cref="Color"/>.</returns>
|
|||
public static Color Compress(Color linear) |
|||
{ |
|||
// TODO: Is there a faster way to do this?
|
|||
float r = Compress(linear.R); |
|||
float g = Compress(linear.G); |
|||
float b = Compress(linear.B); |
|||
|
|||
return new Color(r, g, b, linear.A); |
|||
} |
|||
|
|||
/// <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="Color"/>.</returns>
|
|||
public static Color Expand(Color gamma) |
|||
{ |
|||
// TODO: Is there a faster way to do this?
|
|||
float r = Expand(gamma.R); |
|||
float g = Expand(gamma.G); |
|||
float b = Expand(gamma.B); |
|||
|
|||
return new Color(r, g, b, gamma.A); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a non-premultipled alpha <see cref="Color"/> to a <see cref="Color"/>
|
|||
/// that contains premultiplied alpha.
|
|||
/// </summary>
|
|||
/// <param name="color">The <see cref="Color"/> to convert.</param>
|
|||
/// <returns>The <see cref="Color"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Color FromNonPremultiplied(Color color) |
|||
{ |
|||
return new Color(FromNonPremultiplied(color.backingVector, color.A)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a non-premultiplied alpha Vector4 to a Vector4 that contains premultiplied alpha.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector to convert.</param>
|
|||
/// <param name="alpha">The alpha to use in conversion.</param>
|
|||
/// <returns>The Vector4 with premultiplied alpha.</returns>
|
|||
private static Vector4 FromNonPremultiplied(Vector4 vector, float alpha) |
|||
{ |
|||
return vector * new Vector4(alpha, alpha, alpha, 1); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a premultipled alpha <see cref="Color"/> to a <see cref="Color"/>
|
|||
/// that contains non-premultiplied alpha.
|
|||
/// </summary>
|
|||
/// <param name="color">The <see cref="Color"/> to convert.</param>
|
|||
/// <returns>The <see cref="Color"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Color ToNonPremultiplied(Color color) |
|||
{ |
|||
float a = color.A; |
|||
if (Math.Abs(a) < Epsilon) |
|||
{ |
|||
return new Color(color.backingVector); |
|||
} |
|||
|
|||
return new Color(color.backingVector / new Vector4(a, a, a, 1)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a <see cref="Vector4"/> representation for this <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <returns>A <see cref="Vector4"/> representation for this object.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(this.R, this.G, this.B, this.A); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a <see cref="Vector3"/> representation for this <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <returns>A <see cref="Vector3"/> representation for this object.</returns>
|
|||
public Vector3 ToVector3() |
|||
{ |
|||
return new Vector3(this.R, this.G, this.B); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "Color [ Empty ]"; |
|||
} |
|||
|
|||
return $"Color [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##}, A={this.A:#0.##} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is Color) |
|||
{ |
|||
return this.Equals((Color)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(Color other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool AlmostEquals(Color other, float precision) |
|||
{ |
|||
Vector4 result = Vector4.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision |
|||
&& result.W < precision; |
|||
} |
|||
|
|||
/// <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); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Color"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(Color color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,179 +0,0 @@ |
|||
// <copyright file="ColorConstants.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.Collections.Generic; |
|||
|
|||
/// <summary>
|
|||
/// Provides useful color definitions.
|
|||
/// </summary>
|
|||
public static class ColorConstants |
|||
{ |
|||
/// <summary>
|
|||
/// Provides a lazy, one time method of returning the colors.
|
|||
/// </summary>
|
|||
private static readonly Lazy<Color[]> SafeColors = new Lazy<Color[]>(GetWebSafeColors); |
|||
|
|||
/// <summary>
|
|||
/// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4.
|
|||
/// </summary>
|
|||
public static Color[] WebSafeColors => SafeColors.Value; |
|||
|
|||
/// <summary>
|
|||
/// Returns an array of web safe colors.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
private static Color[] GetWebSafeColors() |
|||
{ |
|||
return new List<Color> |
|||
{ |
|||
Color.AliceBlue, |
|||
Color.AntiqueWhite, |
|||
Color.Aqua, |
|||
Color.Aquamarine, |
|||
Color.Azure, |
|||
Color.Beige, |
|||
Color.Bisque, |
|||
Color.Black, |
|||
Color.BlanchedAlmond, |
|||
Color.Blue, |
|||
Color.BlueViolet, |
|||
Color.Brown, |
|||
Color.BurlyWood, |
|||
Color.CadetBlue, |
|||
Color.Chartreuse, |
|||
Color.Chocolate, |
|||
Color.Coral, |
|||
Color.CornflowerBlue, |
|||
Color.Cornsilk, |
|||
Color.Crimson, |
|||
Color.Cyan, |
|||
Color.DarkBlue, |
|||
Color.DarkCyan, |
|||
Color.DarkGoldenrod, |
|||
Color.DarkGray, |
|||
Color.DarkGreen, |
|||
Color.DarkKhaki, |
|||
Color.DarkMagenta, |
|||
Color.DarkOliveGreen, |
|||
Color.DarkOrange, |
|||
Color.DarkOrchid, |
|||
Color.DarkRed, |
|||
Color.DarkSalmon, |
|||
Color.DarkSeaGreen, |
|||
Color.DarkSlateBlue, |
|||
Color.DarkSlateGray, |
|||
Color.DarkTurquoise, |
|||
Color.DarkViolet, |
|||
Color.DeepPink, |
|||
Color.DeepSkyBlue, |
|||
Color.DimGray, |
|||
Color.DodgerBlue, |
|||
Color.Firebrick, |
|||
Color.FloralWhite, |
|||
Color.ForestGreen, |
|||
Color.Fuchsia, |
|||
Color.Gainsboro, |
|||
Color.GhostWhite, |
|||
Color.Gold, |
|||
Color.Goldenrod, |
|||
Color.Gray, |
|||
Color.Green, |
|||
Color.GreenYellow, |
|||
Color.Honeydew, |
|||
Color.HotPink, |
|||
Color.IndianRed, |
|||
Color.Indigo, |
|||
Color.Ivory, |
|||
Color.Khaki, |
|||
Color.Lavender, |
|||
Color.LavenderBlush, |
|||
Color.LawnGreen, |
|||
Color.LemonChiffon, |
|||
Color.LightBlue, |
|||
Color.LightCoral, |
|||
Color.LightCyan, |
|||
Color.LightGoldenrodYellow, |
|||
Color.LightGray, |
|||
Color.LightGreen, |
|||
Color.LightPink, |
|||
Color.LightSalmon, |
|||
Color.LightSeaGreen, |
|||
Color.LightSkyBlue, |
|||
Color.LightSlateGray, |
|||
Color.LightSteelBlue, |
|||
Color.LightYellow, |
|||
Color.Lime, |
|||
Color.LimeGreen, |
|||
Color.Linen, |
|||
Color.Magenta, |
|||
Color.Maroon, |
|||
Color.MediumAquamarine, |
|||
Color.MediumBlue, |
|||
Color.MediumOrchid, |
|||
Color.MediumPurple, |
|||
Color.MediumSeaGreen, |
|||
Color.MediumSlateBlue, |
|||
Color.MediumSpringGreen, |
|||
Color.MediumTurquoise, |
|||
Color.MediumVioletRed, |
|||
Color.MidnightBlue, |
|||
Color.MintCream, |
|||
Color.MistyRose, |
|||
Color.Moccasin, |
|||
Color.NavajoWhite, |
|||
Color.Navy, |
|||
Color.OldLace, |
|||
Color.Olive, |
|||
Color.OliveDrab, |
|||
Color.Orange, |
|||
Color.OrangeRed, |
|||
Color.Orchid, |
|||
Color.PaleGoldenrod, |
|||
Color.PaleGreen, |
|||
Color.PaleTurquoise, |
|||
Color.PaleVioletRed, |
|||
Color.PapayaWhip, |
|||
Color.PeachPuff, |
|||
Color.Peru, |
|||
Color.Pink, |
|||
Color.Plum, |
|||
Color.PowderBlue, |
|||
Color.Purple, |
|||
Color.RebeccaPurple, |
|||
Color.Red, |
|||
Color.RosyBrown, |
|||
Color.RoyalBlue, |
|||
Color.SaddleBrown, |
|||
Color.Salmon, |
|||
Color.SandyBrown, |
|||
Color.SeaGreen, |
|||
Color.SeaShell, |
|||
Color.Sienna, |
|||
Color.Silver, |
|||
Color.SkyBlue, |
|||
Color.SlateBlue, |
|||
Color.SlateGray, |
|||
Color.Snow, |
|||
Color.SpringGreen, |
|||
Color.SteelBlue, |
|||
Color.Tan, |
|||
Color.Teal, |
|||
Color.Thistle, |
|||
Color.Tomato, |
|||
Color.Transparent, |
|||
Color.Turquoise, |
|||
Color.Violet, |
|||
Color.Wheat, |
|||
Color.White, |
|||
Color.WhiteSmoke, |
|||
Color.Yellow, |
|||
Color.YellowGreen |
|||
}.ToArray(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,728 +0,0 @@ |
|||
// <copyright file="ColorDefinitions.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a four-component color using red, green, blue, and alpha data.
|
|||
/// Each component is stored in premultiplied format multiplied by the alpha component.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public partial struct Color |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F0F8FF.
|
|||
/// </summary>
|
|||
public static readonly Color AliceBlue = new Color(240 / 255f, 248 / 255f, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FAEBD7.
|
|||
/// </summary>
|
|||
public static readonly Color AntiqueWhite = new Color(250 / 255f, 235 / 255f, 215 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00FFFF.
|
|||
/// </summary>
|
|||
public static readonly Color Aqua = new Color(0, 1, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #7FFFD4.
|
|||
/// </summary>
|
|||
public static readonly Color Aquamarine = new Color(127 / 255f, 1, 212 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F0FFFF.
|
|||
/// </summary>
|
|||
public static readonly Color Azure = new Color(240 / 255f, 1, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F5F5DC.
|
|||
/// </summary>
|
|||
public static readonly Color Beige = new Color(245 / 255f, 245 / 255f, 220 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFE4C4.
|
|||
/// </summary>
|
|||
public static readonly Color Bisque = new Color(1, 228 / 255f, 196 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #000000.
|
|||
/// </summary>
|
|||
public static readonly Color Black = new Color(0, 0, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFEBCD.
|
|||
/// </summary>
|
|||
public static readonly Color BlanchedAlmond = new Color(1, 235 / 255f, 205 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #0000FF.
|
|||
/// </summary>
|
|||
public static readonly Color Blue = new Color(0, 0, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #8A2BE2.
|
|||
/// </summary>
|
|||
public static readonly Color BlueViolet = new Color(138 / 255f, 43 / 255f, 226 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #A52A2A.
|
|||
/// </summary>
|
|||
public static readonly Color Brown = new Color(165 / 255f, 42 / 255f, 42 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DEB887.
|
|||
/// </summary>
|
|||
public static readonly Color BurlyWood = new Color(222 / 255f, 184 / 255f, 135 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #5F9EA0.
|
|||
/// </summary>
|
|||
public static readonly Color CadetBlue = new Color(95 / 255f, 158 / 255f, 160 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #7FFF00.
|
|||
/// </summary>
|
|||
public static readonly Color Chartreuse = new Color(127 / 255f, 1, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #D2691E.
|
|||
/// </summary>
|
|||
public static readonly Color Chocolate = new Color(210 / 255f, 105 / 255f, 30 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF7F50.
|
|||
/// </summary>
|
|||
public static readonly Color Coral = new Color(1, 127 / 255f, 80 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #6495ED.
|
|||
/// </summary>
|
|||
public static readonly Color CornflowerBlue = new Color(100 / 255f, 149 / 255f, 237 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFF8DC.
|
|||
/// </summary>
|
|||
public static readonly Color Cornsilk = new Color(1, 248 / 255f, 220 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DC143C.
|
|||
/// </summary>
|
|||
public static readonly Color Crimson = new Color(220 / 255f, 20 / 255f, 60 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00FFFF.
|
|||
/// </summary>
|
|||
public static readonly Color Cyan = new Color(0, 1, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00008B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkBlue = new Color(0, 0, 139 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #008B8B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkCyan = new Color(0, 139 / 255f, 139 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #B8860B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkGoldenrod = new Color(184 / 255f, 134 / 255f, 11 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #A9A9A9.
|
|||
/// </summary>
|
|||
public static readonly Color DarkGray = new Color(169 / 255f, 169 / 255f, 169 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #006400.
|
|||
/// </summary>
|
|||
public static readonly Color DarkGreen = new Color(0, 100 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #BDB76B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkKhaki = new Color(189 / 255f, 183 / 255f, 107 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #8B008B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkMagenta = new Color(139 / 255f, 0, 139 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #556B2F.
|
|||
/// </summary>
|
|||
public static readonly Color DarkOliveGreen = new Color(85 / 255f, 107 / 255f, 47 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF8C00.
|
|||
/// </summary>
|
|||
public static readonly Color DarkOrange = new Color(1, 140 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #9932CC.
|
|||
/// </summary>
|
|||
public static readonly Color DarkOrchid = new Color(153 / 255f, 50 / 255f, 204 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #8B0000.
|
|||
/// </summary>
|
|||
public static readonly Color DarkRed = new Color(139 / 255f, 0, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #E9967A.
|
|||
/// </summary>
|
|||
public static readonly Color DarkSalmon = new Color(233 / 255f, 150 / 255f, 122 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #8FBC8B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkSeaGreen = new Color(143 / 255f, 188 / 255f, 139 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #483D8B.
|
|||
/// </summary>
|
|||
public static readonly Color DarkSlateBlue = new Color(72 / 255f, 61 / 255f, 139 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #2F4F4F.
|
|||
/// </summary>
|
|||
public static readonly Color DarkSlateGray = new Color(47 / 255f, 79 / 255f, 79 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00CED1.
|
|||
/// </summary>
|
|||
public static readonly Color DarkTurquoise = new Color(0, 206 / 255f, 209 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #9400D3.
|
|||
/// </summary>
|
|||
public static readonly Color DarkViolet = new Color(148 / 255f, 0, 211 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF1493.
|
|||
/// </summary>
|
|||
public static readonly Color DeepPink = new Color(1, 20 / 255f, 147 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00BFFF.
|
|||
/// </summary>
|
|||
public static readonly Color DeepSkyBlue = new Color(0, 191 / 255f, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #696969.
|
|||
/// </summary>
|
|||
public static readonly Color DimGray = new Color(105 / 255f, 105 / 255f, 105 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #1E90FF.
|
|||
/// </summary>
|
|||
public static readonly Color DodgerBlue = new Color(30 / 255f, 144 / 255f, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #B22222.
|
|||
/// </summary>
|
|||
public static readonly Color Firebrick = new Color(178 / 255f, 34 / 255f, 34 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFAF0.
|
|||
/// </summary>
|
|||
public static readonly Color FloralWhite = new Color(1, 250 / 255f, 240 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #228B22.
|
|||
/// </summary>
|
|||
public static readonly Color ForestGreen = new Color(34 / 255f, 139 / 255f, 34 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF00FF.
|
|||
/// </summary>
|
|||
public static readonly Color Fuchsia = new Color(1, 0, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DCDCDC.
|
|||
/// </summary>
|
|||
public static readonly Color Gainsboro = new Color(220 / 255f, 220 / 255f, 220 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F8F8FF.
|
|||
/// </summary>
|
|||
public static readonly Color GhostWhite = new Color(248 / 255f, 248 / 255f, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFD700.
|
|||
/// </summary>
|
|||
public static readonly Color Gold = new Color(1, 215 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DAA520.
|
|||
/// </summary>
|
|||
public static readonly Color Goldenrod = new Color(218 / 255f, 165 / 255f, 32 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #808080.
|
|||
/// </summary>
|
|||
public static readonly Color Gray = new Color(128 / 255f, 128 / 255f, 128 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #008000.
|
|||
/// </summary>
|
|||
public static readonly Color Green = new Color(0, 128 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #ADFF2F.
|
|||
/// </summary>
|
|||
public static readonly Color GreenYellow = new Color(173 / 255f, 1, 47 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F0FFF0.
|
|||
/// </summary>
|
|||
public static readonly Color Honeydew = new Color(240 / 255f, 1, 240 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF69B4.
|
|||
/// </summary>
|
|||
public static readonly Color HotPink = new Color(1, 105 / 255f, 180 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #CD5C5C.
|
|||
/// </summary>
|
|||
public static readonly Color IndianRed = new Color(205 / 255f, 92 / 255f, 92 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #4B0082.
|
|||
/// </summary>
|
|||
public static readonly Color Indigo = new Color(75 / 255f, 0, 130 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFFF0.
|
|||
/// </summary>
|
|||
public static readonly Color Ivory = new Color(1, 1, 240 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F0E68C.
|
|||
/// </summary>
|
|||
public static readonly Color Khaki = new Color(240 / 255f, 230 / 255f, 140 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #E6E6FA.
|
|||
/// </summary>
|
|||
public static readonly Color Lavender = new Color(230 / 255f, 230 / 255f, 250 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFF0F5.
|
|||
/// </summary>
|
|||
public static readonly Color LavenderBlush = new Color(1, 240 / 255f, 245 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #7CFC00.
|
|||
/// </summary>
|
|||
public static readonly Color LawnGreen = new Color(124 / 255f, 252 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFACD.
|
|||
/// </summary>
|
|||
public static readonly Color LemonChiffon = new Color(1, 250 / 255f, 205 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #ADD8E6.
|
|||
/// </summary>
|
|||
public static readonly Color LightBlue = new Color(173 / 255f, 216 / 255f, 230 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F08080.
|
|||
/// </summary>
|
|||
public static readonly Color LightCoral = new Color(240 / 255f, 128 / 255f, 128 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #E0FFFF.
|
|||
/// </summary>
|
|||
public static readonly Color LightCyan = new Color(224 / 255f, 1, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FAFAD2.
|
|||
/// </summary>
|
|||
public static readonly Color LightGoldenrodYellow = new Color(250 / 255f, 250 / 255f, 210 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #90EE90.
|
|||
/// </summary>
|
|||
public static readonly Color LightGreen = new Color(144 / 255f, 238 / 255f, 144 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #D3D3D3.
|
|||
/// </summary>
|
|||
public static readonly Color LightGray = new Color(211 / 255f, 211 / 255f, 211 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFB6C1.
|
|||
/// </summary>
|
|||
public static readonly Color LightPink = new Color(1, 182 / 255f, 193 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFA07A.
|
|||
/// </summary>
|
|||
public static readonly Color LightSalmon = new Color(1, 160 / 255f, 122 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #20B2AA.
|
|||
/// </summary>
|
|||
public static readonly Color LightSeaGreen = new Color(32 / 255f, 178 / 255f, 170 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #87CEFA.
|
|||
/// </summary>
|
|||
public static readonly Color LightSkyBlue = new Color(135 / 255f, 206 / 255f, 250 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #778899.
|
|||
/// </summary>
|
|||
public static readonly Color LightSlateGray = new Color(119 / 255f, 136 / 255f, 153 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #B0C4DE.
|
|||
/// </summary>
|
|||
public static readonly Color LightSteelBlue = new Color(176 / 255f, 196 / 255f, 222 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFFE0.
|
|||
/// </summary>
|
|||
public static readonly Color LightYellow = new Color(1, 1, 224 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00FF00.
|
|||
/// </summary>
|
|||
public static readonly Color Lime = new Color(0, 1, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #32CD32.
|
|||
/// </summary>
|
|||
public static readonly Color LimeGreen = new Color(50 / 255f, 205 / 255f, 50 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FAF0E6.
|
|||
/// </summary>
|
|||
public static readonly Color Linen = new Color(250 / 255f, 240 / 255f, 230 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF00FF.
|
|||
/// </summary>
|
|||
public static readonly Color Magenta = new Color(1, 0, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #800000.
|
|||
/// </summary>
|
|||
public static readonly Color Maroon = new Color(128 / 255f, 0, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #66CDAA.
|
|||
/// </summary>
|
|||
public static readonly Color MediumAquamarine = new Color(102 / 255f, 205 / 255f, 170 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #0000CD.
|
|||
/// </summary>
|
|||
public static readonly Color MediumBlue = new Color(0, 0, 205 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #BA55D3.
|
|||
/// </summary>
|
|||
public static readonly Color MediumOrchid = new Color(186 / 255f, 85 / 255f, 211 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #9370DB.
|
|||
/// </summary>
|
|||
public static readonly Color MediumPurple = new Color(147 / 255f, 112 / 255f, 219 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #3CB371.
|
|||
/// </summary>
|
|||
public static readonly Color MediumSeaGreen = new Color(60 / 255f, 179 / 255f, 113 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #7B68EE.
|
|||
/// </summary>
|
|||
public static readonly Color MediumSlateBlue = new Color(123 / 255f, 104 / 255f, 238 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00FA9A.
|
|||
/// </summary>
|
|||
public static readonly Color MediumSpringGreen = new Color(0, 250 / 255f, 154 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #48D1CC.
|
|||
/// </summary>
|
|||
public static readonly Color MediumTurquoise = new Color(72 / 255f, 209 / 255f, 204 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #C71585.
|
|||
/// </summary>
|
|||
public static readonly Color MediumVioletRed = new Color(199 / 255f, 21 / 255f, 133 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #191970.
|
|||
/// </summary>
|
|||
public static readonly Color MidnightBlue = new Color(25 / 255f, 25 / 255f, 112 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F5FFFA.
|
|||
/// </summary>
|
|||
public static readonly Color MintCream = new Color(245 / 255f, 1, 250 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFE4E1.
|
|||
/// </summary>
|
|||
public static readonly Color MistyRose = new Color(1, 228 / 255f, 225 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFE4B5.
|
|||
/// </summary>
|
|||
public static readonly Color Moccasin = new Color(1, 228 / 255f, 181 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFDEAD.
|
|||
/// </summary>
|
|||
public static readonly Color NavajoWhite = new Color(1, 222 / 255f, 173 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #000080.
|
|||
/// </summary>
|
|||
public static readonly Color Navy = new Color(0, 0, 128 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FDF5E6.
|
|||
/// </summary>
|
|||
public static readonly Color OldLace = new Color(253 / 255f, 245 / 255f, 230 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #808000.
|
|||
/// </summary>
|
|||
public static readonly Color Olive = new Color(128 / 255f, 128 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #6B8E23.
|
|||
/// </summary>
|
|||
public static readonly Color OliveDrab = new Color(107 / 255f, 142 / 255f, 35 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFA500.
|
|||
/// </summary>
|
|||
public static readonly Color Orange = new Color(1, 165 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF4500.
|
|||
/// </summary>
|
|||
public static readonly Color OrangeRed = new Color(1, 69 / 255f, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DA70D6.
|
|||
/// </summary>
|
|||
public static readonly Color Orchid = new Color(218 / 255f, 112 / 255f, 214 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #EEE8AA.
|
|||
/// </summary>
|
|||
public static readonly Color PaleGoldenrod = new Color(238 / 255f, 232 / 255f, 170 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #98FB98.
|
|||
/// </summary>
|
|||
public static readonly Color PaleGreen = new Color(152 / 255f, 251 / 255f, 152 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #AFEEEE.
|
|||
/// </summary>
|
|||
public static readonly Color PaleTurquoise = new Color(175 / 255f, 238 / 255f, 238 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DB7093.
|
|||
/// </summary>
|
|||
public static readonly Color PaleVioletRed = new Color(219 / 255f, 112 / 255f, 147 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFEFD5.
|
|||
/// </summary>
|
|||
public static readonly Color PapayaWhip = new Color(1, 239 / 255f, 213 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFDAB9.
|
|||
/// </summary>
|
|||
public static readonly Color PeachPuff = new Color(1, 218 / 255f, 185 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #CD853F.
|
|||
/// </summary>
|
|||
public static readonly Color Peru = new Color(205 / 255f, 133 / 255f, 63 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFC0CB.
|
|||
/// </summary>
|
|||
public static readonly Color Pink = new Color(1, 192 / 255f, 203 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #DDA0DD.
|
|||
/// </summary>
|
|||
public static readonly Color Plum = new Color(221 / 255f, 160 / 255f, 221 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #B0E0E6.
|
|||
/// </summary>
|
|||
public static readonly Color PowderBlue = new Color(176 / 255f, 224 / 255f, 230 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #800080.
|
|||
/// </summary>
|
|||
public static readonly Color Purple = new Color(128 / 255f, 0, 128 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #663399.
|
|||
/// </summary>
|
|||
public static readonly Color RebeccaPurple = new Color(102 / 255f, 51 / 255f, 153 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF0000.
|
|||
/// </summary>
|
|||
public static readonly Color Red = new Color(1, 0, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #BC8F8F.
|
|||
/// </summary>
|
|||
public static readonly Color RosyBrown = new Color(188 / 255f, 143 / 255f, 143 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #4169E1.
|
|||
/// </summary>
|
|||
public static readonly Color RoyalBlue = new Color(65 / 255f, 105 / 255f, 225 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #8B4513.
|
|||
/// </summary>
|
|||
public static readonly Color SaddleBrown = new Color(139 / 255f, 69 / 255f, 19 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FA8072.
|
|||
/// </summary>
|
|||
public static readonly Color Salmon = new Color(250 / 255f, 128 / 255f, 114 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F4A460.
|
|||
/// </summary>
|
|||
public static readonly Color SandyBrown = new Color(244 / 255f, 164 / 255f, 96 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #2E8B57.
|
|||
/// </summary>
|
|||
public static readonly Color SeaGreen = new Color(46 / 255f, 139 / 255f, 87 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFF5EE.
|
|||
/// </summary>
|
|||
public static readonly Color SeaShell = new Color(1, 245 / 255f, 238 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #A0522D.
|
|||
/// </summary>
|
|||
public static readonly Color Sienna = new Color(160 / 255f, 82 / 255f, 45 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #C0C0C0.
|
|||
/// </summary>
|
|||
public static readonly Color Silver = new Color(192 / 255f, 192 / 255f, 192 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #87CEEB.
|
|||
/// </summary>
|
|||
public static readonly Color SkyBlue = new Color(135 / 255f, 206 / 255f, 235 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #6A5ACD.
|
|||
/// </summary>
|
|||
public static readonly Color SlateBlue = new Color(106 / 255f, 90 / 255f, 205 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #708090.
|
|||
/// </summary>
|
|||
public static readonly Color SlateGray = new Color(112 / 255f, 128 / 255f, 144 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFAFA.
|
|||
/// </summary>
|
|||
public static readonly Color Snow = new Color(1, 250 / 255f, 250 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #00FF7F.
|
|||
/// </summary>
|
|||
public static readonly Color SpringGreen = new Color(0, 1, 127 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #4682B4.
|
|||
/// </summary>
|
|||
public static readonly Color SteelBlue = new Color(70 / 255f, 130 / 255f, 180 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #D2B48C.
|
|||
/// </summary>
|
|||
public static readonly Color Tan = new Color(210 / 255f, 180 / 255f, 140 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #008080.
|
|||
/// </summary>
|
|||
public static readonly Color Teal = new Color(0, 128 / 255f, 128 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #D8BFD8.
|
|||
/// </summary>
|
|||
public static readonly Color Thistle = new Color(216 / 255f, 191 / 255f, 216 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FF6347.
|
|||
/// </summary>
|
|||
public static readonly Color Tomato = new Color(1, 99 / 255f, 71 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #40E0D0.
|
|||
/// </summary>
|
|||
public static readonly Color Turquoise = new Color(64 / 255f, 224 / 255f, 208 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #EE82EE.
|
|||
/// </summary>
|
|||
public static readonly Color Violet = new Color(238 / 255f, 130 / 255f, 238 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F5DEB3.
|
|||
/// </summary>
|
|||
public static readonly Color Wheat = new Color(245 / 255f, 222 / 255f, 179 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFFFF.
|
|||
/// </summary>
|
|||
public static readonly Color White = new Color(1, 1, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #F5F5F5.
|
|||
/// </summary>
|
|||
public static readonly Color WhiteSmoke = new Color(245 / 255f, 245 / 255f, 245 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #FFFF00.
|
|||
/// </summary>
|
|||
public static readonly Color Yellow = new Color(1, 1, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="Color"/> matching the W3C definition that has a hex triplet value of #9ACD32.
|
|||
/// </summary>
|
|||
public static readonly Color YellowGreen = new Color(154 / 255f, 205 / 255f, 50 / 255f); |
|||
|
|||
/// <summary>
|
|||
/// Represents a system-defined <see cref="Color"/> that has an ARGB value of #00FFFFFF.
|
|||
/// </summary>
|
|||
public static readonly Color Transparent = new Color(1, 1, 1, 0); |
|||
} |
|||
} |
|||
@ -1,73 +0,0 @@ |
|||
// <copyright file="ColorTransforms.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; |
|||
|
|||
/// <summary>
|
|||
/// Represents a four-component color using red, green, blue, and alpha data.
|
|||
/// Each component is stored in premultiplied format multiplied by the alpha component.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public partial struct Color |
|||
{ |
|||
/// <summary>
|
|||
/// Blends two colors by multiplication.
|
|||
/// <remarks>
|
|||
/// The source color is multiplied by the destination color and replaces the destination.
|
|||
/// The resultant color is always at least as dark as either the source or destination color.
|
|||
/// Multiplying any color with black results in black. Multiplying any color with white preserves the
|
|||
/// original color.
|
|||
/// </remarks>
|
|||
/// </summary>
|
|||
/// <param name="source">The source color.</param>
|
|||
/// <param name="destination">The destination color.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static Color Multiply(Color source, Color destination) |
|||
{ |
|||
if (destination == Color.Black) |
|||
{ |
|||
return Color.Black; |
|||
} |
|||
|
|||
if (destination == Color.White) |
|||
{ |
|||
return source; |
|||
} |
|||
|
|||
return new Color(source.backingVector * destination.backingVector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Linearly interpolates from one color to another based on the given amount.
|
|||
/// </summary>
|
|||
/// <param name="source">The first color value.</param>
|
|||
/// <param name="destination">The second color value.</param>
|
|||
/// <param name="amount">
|
|||
/// The weight value. At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color Lerp(Color source, Color destination, float amount) |
|||
{ |
|||
amount = amount.Clamp(0f, 1f); |
|||
|
|||
if (Math.Abs(source.A - 1) < Epsilon && Math.Abs(destination.A - 1) < Epsilon) |
|||
{ |
|||
return source + ((destination - source) * amount); |
|||
} |
|||
|
|||
// Premultiplied.
|
|||
return (source * (1 - amount)) + destination; |
|||
} |
|||
} |
|||
} |
|||
@ -1,285 +0,0 @@ |
|||
// <copyright file="ColorspaceTransforms.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; |
|||
|
|||
/// <summary>
|
|||
/// Represents a four-component color using red, green, blue, and alpha data.
|
|||
/// Each component is stored in premultiplied format multiplied by the alpha component.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public partial struct Color |
|||
{ |
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="Bgra32"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Bgra32"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(Bgra32 color) |
|||
{ |
|||
return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Cmyk"/> to a
|
|||
/// <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="cmykColor">The instance of <see cref="Cmyk"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(Cmyk cmykColor) |
|||
{ |
|||
float r = (1 - cmykColor.C) * (1 - cmykColor.K); |
|||
float g = (1 - cmykColor.M) * (1 - cmykColor.K); |
|||
float b = (1 - cmykColor.Y) * (1 - cmykColor.K); |
|||
return new Color(r, g, b); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="YCbCr"/> to a
|
|||
/// <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="YCbCr"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(YCbCr color) |
|||
{ |
|||
float y = color.Y; |
|||
float cb = color.Cb - 128; |
|||
float cr = color.Cr - 128; |
|||
|
|||
float r = (float)(y + (1.402 * cr)).Clamp(0, 255) / 255f; |
|||
float g = (float)(y - (0.34414 * cb) - (0.71414 * cr)).Clamp(0, 255) / 255f; |
|||
float b = (float)(y + (1.772 * cb)).Clamp(0, 255) / 255f; |
|||
|
|||
return new Color(r, g, b); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="CieXyz"/> to a
|
|||
/// <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="CieXyz"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(CieXyz color) |
|||
{ |
|||
float x = color.X / 100F; |
|||
float y = color.Y / 100F; |
|||
float z = color.Z / 100F; |
|||
|
|||
// Then XYZ to RGB (multiplication by 100 was done above already)
|
|||
float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F); |
|||
float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); |
|||
float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); |
|||
|
|||
return Color.Compress(new Color(r, g, b)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Hsv"/> to a
|
|||
/// <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="Hsv"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(Hsv color) |
|||
{ |
|||
float s = color.S; |
|||
float v = color.V; |
|||
|
|||
if (Math.Abs(s) < Epsilon) |
|||
{ |
|||
return new Color(v, v, v, 1); |
|||
} |
|||
|
|||
float h = (Math.Abs(color.H - 360) < Epsilon) ? 0 : color.H / 60; |
|||
int i = (int)Math.Truncate(h); |
|||
float f = h - i; |
|||
|
|||
float p = v * (1.0f - s); |
|||
float q = v * (1.0f - (s * f)); |
|||
float t = v * (1.0f - (s * (1.0f - f))); |
|||
|
|||
float r, g, b; |
|||
switch (i) |
|||
{ |
|||
case 0: |
|||
r = v; |
|||
g = t; |
|||
b = p; |
|||
break; |
|||
|
|||
case 1: |
|||
r = q; |
|||
g = v; |
|||
b = p; |
|||
break; |
|||
|
|||
case 2: |
|||
r = p; |
|||
g = v; |
|||
b = t; |
|||
break; |
|||
|
|||
case 3: |
|||
r = p; |
|||
g = q; |
|||
b = v; |
|||
break; |
|||
|
|||
case 4: |
|||
r = t; |
|||
g = p; |
|||
b = v; |
|||
break; |
|||
|
|||
default: |
|||
r = v; |
|||
g = p; |
|||
b = q; |
|||
break; |
|||
} |
|||
|
|||
return new Color(r, g, b); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Hsl"/> to a
|
|||
/// <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="Hsl"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(Hsl color) |
|||
{ |
|||
float rangedH = color.H / 360f; |
|||
float r = 0; |
|||
float g = 0; |
|||
float b = 0; |
|||
float s = color.S; |
|||
float l = color.L; |
|||
|
|||
if (Math.Abs(l) > Epsilon) |
|||
{ |
|||
if (Math.Abs(s) < Epsilon) |
|||
{ |
|||
r = g = b = l; |
|||
} |
|||
else |
|||
{ |
|||
float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s); |
|||
float temp1 = (2f * l) - temp2; |
|||
|
|||
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); |
|||
g = GetColorComponent(temp1, temp2, rangedH); |
|||
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); |
|||
} |
|||
} |
|||
|
|||
return new Color(r, g, b); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="CieLab"/> to a
|
|||
/// <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="cieLabColor">The instance of <see cref="CieLab"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Color"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(CieLab cieLabColor) |
|||
{ |
|||
// First convert back to XYZ...
|
|||
float y = (cieLabColor.L + 16F) / 116F; |
|||
float x = (cieLabColor.A / 500F) + y; |
|||
float z = y - (cieLabColor.B / 200F); |
|||
|
|||
float x3 = x * x * x; |
|||
float y3 = y * y * y; |
|||
float z3 = z * z * z; |
|||
|
|||
x = x3 > 0.008856F ? x3 : (x - 0.137931F) / 7.787F; |
|||
y = (cieLabColor.L > 7.999625F) ? y3 : (cieLabColor.L / 903.3F); |
|||
z = (z3 > 0.008856F) ? z3 : (z - 0.137931F) / 7.787F; |
|||
|
|||
x *= 0.95047F; |
|||
z *= 1.08883F; |
|||
|
|||
// Then XYZ to RGB (multiplication by 100 was done above already)
|
|||
float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F); |
|||
float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); |
|||
float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); |
|||
|
|||
return Color.Compress(new Color(r, g, b)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the color component from the given values.
|
|||
/// </summary>
|
|||
/// <param name="first">The first value.</param>
|
|||
/// <param name="second">The second value.</param>
|
|||
/// <param name="third">The third value.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
private static float GetColorComponent(float first, float second, float third) |
|||
{ |
|||
third = MoveIntoRange(third); |
|||
if (third < 0.1666667F) |
|||
{ |
|||
return first + ((second - first) * 6.0f * third); |
|||
} |
|||
|
|||
if (third < 0.5) |
|||
{ |
|||
return second; |
|||
} |
|||
|
|||
if (third < 0.6666667F) |
|||
{ |
|||
return first + ((second - first) * (0.6666667F - third) * 6.0f); |
|||
} |
|||
|
|||
return first; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Moves the specific value within the acceptable range for
|
|||
/// conversion.
|
|||
/// <remarks>Used for converting <see cref="Hsl"/> colors to this type.</remarks>
|
|||
/// </summary>
|
|||
/// <param name="value">The value to shift.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
private static float MoveIntoRange(float value) |
|||
{ |
|||
if (value < 0.0) |
|||
{ |
|||
value += 1.0f; |
|||
} |
|||
else if (value > 1.0) |
|||
{ |
|||
value -= 1.0f; |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
@ -1,168 +0,0 @@ |
|||
//// <copyright file="Bgra32.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.ComponentModel;
|
|||
// using System.Numerics;
|
|||
|
|||
// /// <summary>
|
|||
// /// Represents an BGRA (blue, green, red, alpha) color.
|
|||
// /// </summary>
|
|||
// public struct Bgra32 : IEquatable<Bgra32>
|
|||
// {
|
|||
// /// <summary>
|
|||
// /// Represents a 32 bit <see cref="Bgra32"/> that has B, G, R, and A values set to zero.
|
|||
// /// </summary>
|
|||
// public static readonly Bgra32 Empty = default(Bgra32);
|
|||
|
|||
// /// <summary>
|
|||
// /// The backing vector for SIMD support.
|
|||
// /// </summary>
|
|||
// private Vector4 backingVector;
|
|||
|
|||
// /// <summary>
|
|||
// /// Initializes a new instance of the <see cref="Bgra32"/> struct.
|
|||
// /// </summary>
|
|||
// /// <param name="b">The blue component of this <see cref="Bgra32"/>.</param>
|
|||
// /// <param name="g">The green component of this <see cref="Bgra32"/>.</param>
|
|||
// /// <param name="r">The red component of this <see cref="Bgra32"/>.</param>
|
|||
// /// <param name="a">The alpha component of this <see cref="Bgra32"/>.</param>
|
|||
// public Bgra32(byte b, byte g, byte r, byte a = 255)
|
|||
// : this()
|
|||
// {
|
|||
// this.backingVector = Vector4.Clamp(new Vector4(b, g, r, a), Vector4.Zero, new Vector4(255));
|
|||
// }
|
|||
|
|||
// /// <summary>
|
|||
// /// Gets the blue component of the color
|
|||
// /// </summary>
|
|||
// public byte B => (byte)this.backingVector.X;
|
|||
|
|||
// /// <summary>
|
|||
// /// Gets the green component of the color
|
|||
// /// </summary>
|
|||
// public byte G => (byte)this.backingVector.Y;
|
|||
|
|||
// /// <summary>
|
|||
// /// Gets the red component of the color
|
|||
// /// </summary>
|
|||
// public byte R => (byte)this.backingVector.Z;
|
|||
|
|||
// /// <summary>
|
|||
// /// Gets the alpha component of the color
|
|||
// /// </summary>
|
|||
// public byte A => (byte)this.backingVector.W;
|
|||
|
|||
// /// <summary>
|
|||
// /// Gets the <see cref="Bgra32"/> integer representation of the color.
|
|||
// /// </summary>
|
|||
// public int Bgra => (this.R << 16) | (this.G << 8) | (this.B << 0) | (this.A << 24);
|
|||
|
|||
// /// <summary>
|
|||
// /// Gets a value indicating whether this <see cref="Bgra32"/> is empty.
|
|||
// /// </summary>
|
|||
// [EditorBrowsable(EditorBrowsableState.Never)]
|
|||
// public bool IsEmpty => this.Equals(Empty);
|
|||
|
|||
// /// <summary>
|
|||
// /// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
// /// <see cref="Bgra32"/>.
|
|||
// /// </summary>
|
|||
// /// <param name="color">
|
|||
// /// The instance of <see cref="Color"/> to convert.
|
|||
// /// </param>
|
|||
// /// <returns>
|
|||
// /// An instance of <see cref="Bgra32"/>.
|
|||
// /// </returns>
|
|||
// public static implicit operator Bgra32(Color color)
|
|||
// {
|
|||
// color = color.Limited * 255f;
|
|||
// return new Bgra32((byte)color.B, (byte)color.G, (byte)color.R, (byte)color.A);
|
|||
// }
|
|||
|
|||
// /// <summary>
|
|||
// /// Compares two <see cref="Bgra32"/> objects for equality.
|
|||
// /// </summary>
|
|||
// /// <param name="left">
|
|||
// /// The <see cref="Bgra32"/> on the left side of the operand.
|
|||
// /// </param>
|
|||
// /// <param name="right">
|
|||
// /// The <see cref="Bgra32"/> on the right side of the operand.
|
|||
// /// </param>
|
|||
// /// <returns>
|
|||
// /// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
// /// </returns>
|
|||
// public static bool operator ==(Bgra32 left, Bgra32 right)
|
|||
// {
|
|||
// return left.Equals(right);
|
|||
// }
|
|||
|
|||
// /// <summary>
|
|||
// /// Compares two <see cref="Bgra32"/> objects for inequality.
|
|||
// /// </summary>
|
|||
// /// <param name="left">
|
|||
// /// The <see cref="Bgra32"/> on the left side of the operand.
|
|||
// /// </param>
|
|||
// /// <param name="right">
|
|||
// /// The <see cref="Bgra32"/> on the right side of the operand.
|
|||
// /// </param>
|
|||
// /// <returns>
|
|||
// /// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
// /// </returns>
|
|||
// public static bool operator !=(Bgra32 left, Bgra32 right)
|
|||
// {
|
|||
// return !left.Equals(right);
|
|||
// }
|
|||
|
|||
// /// <inheritdoc/>
|
|||
// public override bool Equals(object obj)
|
|||
// {
|
|||
// if (obj is Bgra32)
|
|||
// {
|
|||
// Bgra32 color = (Bgra32)obj;
|
|||
|
|||
// return this.backingVector == color.backingVector;
|
|||
// }
|
|||
|
|||
// return false;
|
|||
// }
|
|||
|
|||
// /// <inheritdoc/>
|
|||
// public override int GetHashCode()
|
|||
// {
|
|||
// return GetHashCode(this);
|
|||
// }
|
|||
|
|||
// /// <inheritdoc/>
|
|||
// public override string ToString()
|
|||
// {
|
|||
// if (this.IsEmpty)
|
|||
// {
|
|||
// return "Bgra32 [ Empty ]";
|
|||
// }
|
|||
|
|||
// return $"Bgra32 [ B={this.B}, G={this.G}, R={this.R}, A={this.A} ]";
|
|||
// }
|
|||
|
|||
// /// <inheritdoc/>
|
|||
// public bool Equals(Bgra32 other)
|
|||
// {
|
|||
// return this.backingVector.Equals(other.backingVector);
|
|||
// }
|
|||
|
|||
// /// <summary>
|
|||
// /// Returns the hash code for this instance.
|
|||
// /// </summary>
|
|||
// /// <param name="color">
|
|||
// /// The instance of <see cref="Cmyk"/> to return the hash code for.
|
|||
// /// </param>
|
|||
// /// <returns>
|
|||
// /// A 32-bit signed integer that is the hash code for this instance.
|
|||
// /// </returns>
|
|||
// private static int GetHashCode(Bgra32 color) => color.backingVector.GetHashCode();
|
|||
// }
|
|||
//}
|
|||
@ -1,193 +0,0 @@ |
|||
// <copyright file="CieLab.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.ComponentModel; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents an CIE LAB 1976 color.
|
|||
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
|
|||
/// </summary>
|
|||
public struct CieLab : IEquatable<CieLab>, IAlmostEquatable<CieLab, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="CieLab"/> that has L, A, B values set to zero.
|
|||
/// </summary>
|
|||
public static readonly CieLab Empty = default(CieLab); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLab"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="l">The lightness dimension.</param>
|
|||
/// <param name="a">The a (green - magenta) component.</param>
|
|||
/// <param name="b">The b (blue - yellow) component.</param>
|
|||
public CieLab(float l, float a, float b) |
|||
: this() |
|||
{ |
|||
this.backingVector = Vector3.Clamp(new Vector3(l, a, b), new Vector3(0, -100, -100), new Vector3(100)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the lightness dimension.
|
|||
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
|
|||
/// </summary>
|
|||
public float L => this.backingVector.X; |
|||
|
|||
/// <summary>
|
|||
/// Gets the a color component.
|
|||
/// <remarks>Negative is green, positive magenta.</remarks>
|
|||
/// </summary>
|
|||
public float A => this.backingVector.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the b color component.
|
|||
/// <remarks>Negative is blue, positive is yellow</remarks>
|
|||
/// </summary>
|
|||
public float B => this.backingVector.Z; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="CieLab"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="CieLab"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Bgra32"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="CieLab"/>.
|
|||
/// </returns>
|
|||
public static implicit operator CieLab(Color color) |
|||
{ |
|||
// First convert to CIE XYZ
|
|||
color = Color.Expand(color); |
|||
|
|||
float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); |
|||
float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); |
|||
float z = (color.R * 0.0193F) + (color.G * 0.1192F) + (color.B * 0.9505F); |
|||
|
|||
// Now to LAB
|
|||
x /= 0.95047F; |
|||
//y /= 1F;
|
|||
z /= 1.08883F; |
|||
|
|||
x = x > 0.008856F ? (float)Math.Pow(x, 0.3333333F) : (903.3F * x + 16F) / 116F; |
|||
y = y > 0.008856F ? (float)Math.Pow(y, 0.3333333F) : (903.3F * y + 16F) / 116F; |
|||
z = z > 0.008856F ? (float)Math.Pow(z, 0.3333333F) : (903.3F * z + 16F) / 116F; |
|||
|
|||
float l = Math.Max(0, (116F * y) - 16F); |
|||
float a = 500F * (x - y); |
|||
float b = 200F * (y - z); |
|||
|
|||
return new CieLab(l, a, b); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieLab"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieLab"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieLab"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(CieLab left, CieLab right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieLab"/> objects for inequality
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieLab"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieLab"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(CieLab left, CieLab right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "CieLab [Empty]"; |
|||
} |
|||
|
|||
return $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is CieLab) |
|||
{ |
|||
return this.Equals((CieLab)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(CieLab other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool AlmostEquals(CieLab other, float precision) |
|||
{ |
|||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="CieLab"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(CieLab color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,184 +0,0 @@ |
|||
// <copyright file="CieXyz.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.ComponentModel; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents an CIE 1931 color
|
|||
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space"/>
|
|||
/// </summary>
|
|||
public struct CieXyz : IEquatable<CieXyz>, IAlmostEquatable<CieXyz, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="CieXyz"/> that has Y, Cb, and Cr values set to zero.
|
|||
/// </summary>
|
|||
public static readonly CieXyz Empty = default(CieXyz); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieXyz"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="y">The y luminance component.</param>
|
|||
/// <param name="x">X is a mix (a linear combination) of cone response curves chosen to be nonnegative</param>
|
|||
/// <param name="z">Z is quasi-equal to blue stimulation, or the S cone of the human eye.</param>
|
|||
public CieXyz(float x, float y, float z) |
|||
: this() |
|||
{ |
|||
// Not clamping as documentation about this space seems to indicate "usual" ranges
|
|||
this.backingVector = new Vector3(x, y, z); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the Y luminance component.
|
|||
/// <remarks>A value ranging between 380 and 780.</remarks>
|
|||
/// </summary>
|
|||
public float X => this.backingVector.X; |
|||
|
|||
/// <summary>
|
|||
/// Gets the Cb chroma component.
|
|||
/// <remarks>A value ranging between 380 and 780.</remarks>
|
|||
/// </summary>
|
|||
public float Y => this.backingVector.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the Cr chroma component.
|
|||
/// <remarks>A value ranging between 380 and 780.</remarks>
|
|||
/// </summary>
|
|||
public float Z => this.backingVector.Z; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="CieXyz"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="CieXyz"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Color"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="CieXyz"/>.
|
|||
/// </returns>
|
|||
public static implicit operator CieXyz(Color color) |
|||
{ |
|||
color = Color.Expand(color); |
|||
|
|||
float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); |
|||
float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); |
|||
float z = (color.R * 0.0193F) + (color.G * 0.1192F) + (color.B * 0.9505F); |
|||
|
|||
x *= 100F; |
|||
y *= 100F; |
|||
z *= 100F; |
|||
|
|||
return new CieXyz(x, y, z); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieXyz"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieXyz"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieXyz"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(CieXyz left, CieXyz right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieXyz"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieXyz"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieXyz"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(CieXyz left, CieXyz right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "CieXyz [ Empty ]"; |
|||
} |
|||
|
|||
return $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is CieXyz) |
|||
{ |
|||
return this.Equals((CieXyz)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(CieXyz other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool AlmostEquals(CieXyz other, float precision) |
|||
{ |
|||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Hsv"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(CieXyz color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,197 +0,0 @@ |
|||
// <copyright file="Cmyk.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.ComponentModel; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
|
|||
/// </summary>
|
|||
public struct Cmyk : IEquatable<Cmyk>, IAlmostEquatable<Cmyk, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Cmyk"/> that has C, M, Y, and K values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Cmyk Empty = default(Cmyk); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector4 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="c">The cyan component.</param>
|
|||
/// <param name="m">The magenta component.</param>
|
|||
/// <param name="y">The yellow component.</param>
|
|||
/// <param name="k">The keyline black component.</param>
|
|||
public Cmyk(float c, float m, float y, float k) |
|||
: this() |
|||
{ |
|||
this.backingVector = Vector4.Clamp(new Vector4(c, m, y, k), Vector4.Zero, Vector4.One); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the cyan color component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float C => this.backingVector.X; |
|||
|
|||
/// <summary>
|
|||
/// Gets the magenta color component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float M => this.backingVector.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the yellow color component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float Y => this.backingVector.Z; |
|||
|
|||
/// <summary>
|
|||
/// Gets the keyline black color component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float K => this.backingVector.W; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Cmyk"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="Cmyk"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Bgra32"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Cmyk"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Cmyk(Color color) |
|||
{ |
|||
color = color.Limited; |
|||
|
|||
float c = 1f - color.R; |
|||
float m = 1f - color.G; |
|||
float y = 1f - color.B; |
|||
|
|||
float k = Math.Min(c, Math.Min(m, y)); |
|||
|
|||
if (Math.Abs(k - 1.0f) <= Epsilon) |
|||
{ |
|||
return new Cmyk(0, 0, 0, 1); |
|||
} |
|||
|
|||
c = (c - k) / (1 - k); |
|||
m = (m - k) / (1 - k); |
|||
y = (y - k) / (1 - k); |
|||
|
|||
return new Cmyk(c, m, y, k); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Cmyk"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Cmyk"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Cmyk"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Cmyk left, Cmyk right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Cmyk"/> objects for inequality
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Cmyk"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Cmyk"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Cmyk left, Cmyk right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "Cmyk [Empty]"; |
|||
} |
|||
|
|||
return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is Cmyk) |
|||
{ |
|||
return this.Equals((Cmyk)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(Cmyk other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool AlmostEquals(Cmyk other, float precision) |
|||
{ |
|||
Vector4 result = Vector4.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision |
|||
&& result.W < precision; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Cmyk"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(Cmyk color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,213 +0,0 @@ |
|||
// <copyright file="Hsl.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.ComponentModel; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents a Hsl (hue, saturation, lightness) color.
|
|||
/// </summary>
|
|||
public struct Hsl : IEquatable<Hsl>, IAlmostEquatable<Hsl, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Hsl"/> that has H, S, and L values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Hsl Empty = default(Hsl); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Hsl"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="h">The h hue component.</param>
|
|||
/// <param name="s">The s saturation component.</param>
|
|||
/// <param name="l">The l value (lightness) component.</param>
|
|||
public Hsl(float h, float s, float l) |
|||
{ |
|||
this.backingVector = Vector3.Clamp(new Vector3(h, s, l), Vector3.Zero, new Vector3(360, 1, 1)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the hue component.
|
|||
/// <remarks>A value ranging between 0 and 360.</remarks>
|
|||
/// </summary>
|
|||
public float H => this.backingVector.X; |
|||
|
|||
/// <summary>
|
|||
/// Gets the saturation component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float S => this.backingVector.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the lightness component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float L => this.backingVector.Z; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Hsl"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="Hsl"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Hsl"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Hsl(Color color) |
|||
{ |
|||
color = Color.ToNonPremultiplied(color.Limited); |
|||
float r = color.R; |
|||
float g = color.G; |
|||
float b = color.B; |
|||
|
|||
float max = Math.Max(r, Math.Max(g, b)); |
|||
float min = Math.Min(r, Math.Min(g, b)); |
|||
float chroma = max - min; |
|||
float h = 0; |
|||
float s = 0; |
|||
float l = (max + min) / 2; |
|||
|
|||
if (Math.Abs(chroma) < Epsilon) |
|||
{ |
|||
return new Hsl(0, s, l); |
|||
} |
|||
|
|||
if (Math.Abs(r - max) < Epsilon) |
|||
{ |
|||
h = (g - b) / chroma; |
|||
} |
|||
else if (Math.Abs(g - max) < Epsilon) |
|||
{ |
|||
h = 2 + ((b - r) / chroma); |
|||
} |
|||
else if (Math.Abs(b - max) < Epsilon) |
|||
{ |
|||
h = 4 + ((r - g) / chroma); |
|||
} |
|||
|
|||
h *= 60; |
|||
if (h < 0.0) |
|||
{ |
|||
h += 360; |
|||
} |
|||
|
|||
if (l <= .5f) |
|||
{ |
|||
s = chroma / (max + min); |
|||
} |
|||
else { |
|||
s = chroma / (2 - chroma); |
|||
} |
|||
|
|||
return new Hsl(h, s, l); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Hsl"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Hsl"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Hsl"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Hsl left, Hsl right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Hsl"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Hsl"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Hsl"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Hsl left, Hsl right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "Hsl [ Empty ]"; |
|||
} |
|||
|
|||
return $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is Hsl) |
|||
{ |
|||
return this.Equals((Hsl)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(Hsl other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool AlmostEquals(Hsl other, float precision) |
|||
{ |
|||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Hsl"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(Hsl color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,207 +0,0 @@ |
|||
// <copyright file="Hsv.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.ComponentModel; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
|
|||
/// </summary>
|
|||
public struct Hsv : IEquatable<Hsv>, IAlmostEquatable<Hsv, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Hsv"/> that has H, S, and V values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Hsv Empty = default(Hsv); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Hsv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="h">The h hue component.</param>
|
|||
/// <param name="s">The s saturation component.</param>
|
|||
/// <param name="v">The v value (brightness) component.</param>
|
|||
public Hsv(float h, float s, float v) |
|||
{ |
|||
this.backingVector = Vector3.Clamp(new Vector3(h, s, v), Vector3.Zero, new Vector3(360, 1, 1)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the hue component.
|
|||
/// <remarks>A value ranging between 0 and 360.</remarks>
|
|||
/// </summary>
|
|||
public float H => this.backingVector.X; |
|||
|
|||
/// <summary>
|
|||
/// Gets the saturation component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float S => this.backingVector.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the value (brightness) component.
|
|||
/// <remarks>A value ranging between 0 and 1.</remarks>
|
|||
/// </summary>
|
|||
public float V => this.backingVector.Z; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Hsv"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="Hsv"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Hsv"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Hsv(Color color) |
|||
{ |
|||
color = Color.ToNonPremultiplied(color.Limited); |
|||
float r = color.R; |
|||
float g = color.G; |
|||
float b = color.B; |
|||
|
|||
float max = Math.Max(r, Math.Max(g, b)); |
|||
float min = Math.Min(r, Math.Min(g, b)); |
|||
float chroma = max - min; |
|||
float h = 0; |
|||
float s = 0; |
|||
float v = max; |
|||
|
|||
if (Math.Abs(chroma) < Epsilon) |
|||
{ |
|||
return new Hsv(0, s, v); |
|||
} |
|||
|
|||
if (Math.Abs(r - max) < Epsilon) |
|||
{ |
|||
h = (g - b) / chroma; |
|||
} |
|||
else if (Math.Abs(g - max) < Epsilon) |
|||
{ |
|||
h = 2 + ((b - r) / chroma); |
|||
} |
|||
else if (Math.Abs(b - max) < Epsilon) |
|||
{ |
|||
h = 4 + ((r - g) / chroma); |
|||
} |
|||
|
|||
h *= 60; |
|||
if (h < 0.0) |
|||
{ |
|||
h += 360; |
|||
} |
|||
|
|||
s = chroma / v; |
|||
|
|||
return new Hsv(h, s, v); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Hsv"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Hsv"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Hsv"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Hsv left, Hsv right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Hsv"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Hsv"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Hsv"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Hsv left, Hsv right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "Hsv [ Empty ]"; |
|||
} |
|||
|
|||
return $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is Hsv) |
|||
{ |
|||
return this.Equals((Hsv)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(Hsv other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool AlmostEquals(Hsv other, float precision) |
|||
{ |
|||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Hsv"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(Hsv color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,183 +0,0 @@ |
|||
// <copyright file="YCbCr.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.ComponentModel; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents an YCbCr (luminance, chroma, chroma) color conforming to the
|
|||
/// Full range standard used in digital imaging systems.
|
|||
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
|
|||
/// </summary>
|
|||
public struct YCbCr : IEquatable<YCbCr>, IAlmostEquatable<YCbCr, float> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="YCbCr"/> that has Y, Cb, and Cr values set to zero.
|
|||
/// </summary>
|
|||
public static readonly YCbCr Empty = default(YCbCr); |
|||
|
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="YCbCr"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="y">The y luminance component.</param>
|
|||
/// <param name="cb">The cb chroma component.</param>
|
|||
/// <param name="cr">The cr chroma component.</param>
|
|||
public YCbCr(float y, float cb, float cr) |
|||
: this() |
|||
{ |
|||
this.backingVector = Vector3.Clamp(new Vector3(y, cb, cr), Vector3.Zero, new Vector3(255)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the Y luminance component.
|
|||
/// <remarks>A value ranging between 0 and 255.</remarks>
|
|||
/// </summary>
|
|||
public float Y => this.backingVector.X; |
|||
|
|||
/// <summary>
|
|||
/// Gets the Cb chroma component.
|
|||
/// <remarks>A value ranging between 0 and 255.</remarks>
|
|||
/// </summary>
|
|||
public float Cb => this.backingVector.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the Cr chroma component.
|
|||
/// <remarks>A value ranging between 0 and 255.</remarks>
|
|||
/// </summary>
|
|||
public float Cr => this.backingVector.Z; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="YCbCr"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="YCbCr"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Color"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="YCbCr"/>.
|
|||
/// </returns>
|
|||
public static implicit operator YCbCr(Color color) |
|||
{ |
|||
color = Color.ToNonPremultiplied(color.Limited) * 255f; |
|||
float r = color.R; |
|||
float g = color.G; |
|||
float b = color.B; |
|||
|
|||
float y = (float)((0.299 * r) + (0.587 * g) + (0.114 * b)); |
|||
float cb = 128 + (float)((-0.168736 * r) - (0.331264 * g) + (0.5 * b)); |
|||
float cr = 128 + (float)((0.5 * r) - (0.418688 * g) - (0.081312 * b)); |
|||
|
|||
return new YCbCr(y, cb, cr); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="YCbCr"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="YCbCr"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="YCbCr"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(YCbCr left, YCbCr right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="YCbCr"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="YCbCr"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="YCbCr"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(YCbCr left, YCbCr right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return GetHashCode(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "YCbCr [ Empty ]"; |
|||
} |
|||
|
|||
return $"YCbCr [ Y={this.Y:#0.##}, Cb={this.Cb:#0.##}, Cr={this.Cr:#0.##} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is YCbCr) |
|||
{ |
|||
return this.Equals((YCbCr)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(YCbCr other) |
|||
{ |
|||
return this.AlmostEquals(other, Epsilon); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool AlmostEquals(YCbCr other, float precision) |
|||
{ |
|||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return result.X < precision |
|||
&& result.Y < precision |
|||
&& result.Z < precision; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the hash code for this instance.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Hsv"/> to return the hash code for.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that is the hash code for this instance.
|
|||
/// </returns>
|
|||
private static int GetHashCode(YCbCr color) => color.backingVector.GetHashCode(); |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="IAlmostEquatable.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; |
|||
|
|||
/// <summary>
|
|||
/// Defines a generalized method that a value type or class implements to create
|
|||
/// a type-specific method for determining approximate equality of instances.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of objects to compare.</typeparam>
|
|||
/// <typeparam name="TP">The object specifying the type to specify precision with.</typeparam>
|
|||
public interface IAlmostEquatable<T, TP> where TP : struct, IComparable<TP> |
|||
{ |
|||
/// <summary>
|
|||
/// Indicates whether the current object is equal to another object of the same type
|
|||
/// when compared to the specified precision level.
|
|||
/// </summary>
|
|||
/// <param name="other">An object to compare with this object.</param>
|
|||
/// <param name="precision">The object specifying the level of precision.</param>
|
|||
/// <returns>
|
|||
/// true if the current object is equal to the other parameter; otherwise, false.
|
|||
/// </returns>
|
|||
bool AlmostEquals(T other, TP precision); |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
// <copyright file="RgbaComponent.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerates the RGBA (red, green, blue, alpha) color components.
|
|||
/// </summary>
|
|||
public enum RgbaComponent |
|||
{ |
|||
/// <summary>
|
|||
/// The blue component.
|
|||
/// </summary>
|
|||
B = 0, |
|||
|
|||
/// <summary>
|
|||
/// The green component.
|
|||
/// </summary>
|
|||
G = 1, |
|||
|
|||
/// <summary>
|
|||
/// The red component.
|
|||
/// </summary>
|
|||
R = 2, |
|||
|
|||
/// <summary>
|
|||
/// The alpha component.
|
|||
/// </summary>
|
|||
A = 3 |
|||
} |
|||
} |
|||
@ -1,45 +0,0 @@ |
|||
// <copyright file="ImageFormatException.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; |
|||
|
|||
/// <summary>
|
|||
/// The exception that is thrown when the library tries to load
|
|||
/// an image, which has an invalid format.
|
|||
/// </summary>
|
|||
public class ImageFormatException : Exception |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageFormatException"/> class.
|
|||
/// </summary>
|
|||
public ImageFormatException() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageFormatException"/> class with the name of the
|
|||
/// parameter that causes this exception.
|
|||
/// </summary>
|
|||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|||
public ImageFormatException(string errorMessage) |
|||
: base(errorMessage) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageFormatException"/> class with a specified
|
|||
/// error message and the exception that is the cause of this exception.
|
|||
/// </summary>
|
|||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic)
|
|||
/// if no inner exception is specified.</param>
|
|||
public ImageFormatException(string errorMessage, Exception innerException) |
|||
: base(errorMessage, innerException) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
// <copyright file="ImageProcessingException.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; |
|||
|
|||
/// <summary>
|
|||
/// The exception that is thrown when an error occurs when applying a process to an image.
|
|||
/// </summary>
|
|||
public class ImageProcessingException : Exception |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageProcessingException"/> class.
|
|||
/// </summary>
|
|||
public ImageProcessingException() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageProcessingException"/> class with the name of the
|
|||
/// parameter that causes this exception.
|
|||
/// </summary>
|
|||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|||
public ImageProcessingException(string errorMessage) |
|||
: base(errorMessage) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageProcessingException"/> class with a specified
|
|||
/// error message and the exception that is the cause of this exception.
|
|||
/// </summary>
|
|||
/// <param name="errorMessage">The error message that explains the reason for this exception.</param>
|
|||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic)
|
|||
/// if no inner exception is specified.</param>
|
|||
public ImageProcessingException(string errorMessage, Exception innerException) |
|||
: base(errorMessage, innerException) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
// <copyright file="ByteExtensions.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; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="byte"/> struct.
|
|||
/// </summary>
|
|||
internal static class ByteExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Converts a byte array to a new array where each value in the original array is represented
|
|||
/// by a the specified number of bits.
|
|||
/// </summary>
|
|||
/// <param name="bytes">The bytes to convert from. Cannot be null.</param>
|
|||
/// <param name="bits">The number of bits per value.</param>
|
|||
/// <returns>The resulting <see cref="T:byte[]"/> array. Is never null.</returns>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="bytes"/> is null.</exception>
|
|||
/// <exception cref="ArgumentException"><paramref name="bits"/> is less than or equals than zero.</exception>
|
|||
public static byte[] ToArrayByBitsLength(this byte[] bytes, int bits) |
|||
{ |
|||
Guard.NotNull(bytes, "bytes"); |
|||
Guard.MustBeGreaterThan(bits, 0, "bits"); |
|||
|
|||
byte[] result; |
|||
|
|||
if (bits < 8) |
|||
{ |
|||
result = new byte[bytes.Length * 8 / bits]; |
|||
|
|||
// BUGFIX I dont think it should be there, but I am not sure if it breaks something else
|
|||
// int factor = (int)Math.Pow(2, bits) - 1;
|
|||
int mask = 0xFF >> (8 - bits); |
|||
int resultOffset = 0; |
|||
|
|||
foreach (byte b in bytes) |
|||
{ |
|||
for (int shift = 0; shift < 8; shift += bits) |
|||
{ |
|||
int colorIndex = (b >> (8 - bits - shift)) & mask; // * (255 / factor);
|
|||
|
|||
result[resultOffset] = (byte)colorIndex; |
|||
|
|||
resultOffset++; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
result = bytes; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -1,145 +0,0 @@ |
|||
// <copyright file="ComparableExtensions.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; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for classes that implement <see cref="IComparable{T}"/>.
|
|||
/// </summary>
|
|||
internal static class ComparableExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Restricts a <see cref="byte"/> to be within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="value">The The value to clamp.</param>
|
|||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="byte"/> representing the clamped value.
|
|||
/// </returns>
|
|||
public static byte Clamp(this byte value, byte min, byte max) |
|||
{ |
|||
// Order is important here as someone might set min to higher than max.
|
|||
if (value > max) |
|||
{ |
|||
return max; |
|||
} |
|||
|
|||
if (value < min) |
|||
{ |
|||
return min; |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Restricts a <see cref="int"/> to be within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="value">The The value to clamp.</param>
|
|||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="int"/> representing the clamped value.
|
|||
/// </returns>
|
|||
public static int Clamp(this int value, int min, int max) |
|||
{ |
|||
if (value > max) |
|||
{ |
|||
return max; |
|||
} |
|||
|
|||
if (value < min) |
|||
{ |
|||
return min; |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Restricts a <see cref="float"/> to be within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="value">The The value to clamp.</param>
|
|||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/> representing the clamped value.
|
|||
/// </returns>
|
|||
public static float Clamp(this float value, float min, float max) |
|||
{ |
|||
if (value > max) |
|||
{ |
|||
return max; |
|||
} |
|||
|
|||
if (value < min) |
|||
{ |
|||
return min; |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Restricts a <see cref="double"/> to be within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="value">The The value to clamp.</param>
|
|||
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
|
|||
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="double"/> representing the clamped value.
|
|||
/// </returns>
|
|||
public static double Clamp(this double value, double min, double max) |
|||
{ |
|||
if (value > max) |
|||
{ |
|||
return max; |
|||
} |
|||
|
|||
if (value < min) |
|||
{ |
|||
return min; |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts an <see cref="int"/> to a <see cref="byte"/> first restricting the value between the
|
|||
/// minimum and maximum allowable ranges.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="int"/> this method extends.</param>
|
|||
/// <returns>The <see cref="byte"/></returns>
|
|||
public static byte ToByte(this int value) |
|||
{ |
|||
return (byte)value.Clamp(0, 255); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts an <see cref="float"/> to a <see cref="byte"/> first restricting the value between the
|
|||
/// minimum and maximum allowable ranges.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="float"/> this method extends.</param>
|
|||
/// <returns>The <see cref="byte"/></returns>
|
|||
public static byte ToByte(this float value) |
|||
{ |
|||
return (byte)value.Clamp(0, 255); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts an <see cref="double"/> to a <see cref="byte"/> first restricting the value between the
|
|||
/// minimum and maximum allowable ranges.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="double"/> this method extends.</param>
|
|||
/// <returns>The <see cref="byte"/></returns>
|
|||
public static byte ToByte(this double value) |
|||
{ |
|||
return (byte)value.Clamp(0, 255); |
|||
} |
|||
} |
|||
} |
|||
@ -1,88 +0,0 @@ |
|||
// <copyright file="EnumerableExtensions.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.Collections.Generic; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates a series of time saving extension methods to the <see cref="T:System.Collections.IEnumerable"/> interface.
|
|||
/// </summary>
|
|||
public static class EnumerableExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Generates a sequence of integral numbers within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="fromInclusive">
|
|||
/// The start index, inclusive.
|
|||
/// </param>
|
|||
/// <param name="toExclusive">
|
|||
/// The end index, exclusive.
|
|||
/// </param>
|
|||
/// <param name="step">
|
|||
/// The incremental step.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|||
/// </returns>
|
|||
public static IEnumerable<int> SteppedRange(int fromInclusive, int toExclusive, int step) |
|||
{ |
|||
// Borrowed from Enumerable.Range
|
|||
long num = (fromInclusive + toExclusive) - 1L; |
|||
if ((toExclusive < 0) || (num > 0x7fffffffL)) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(toExclusive)); |
|||
} |
|||
|
|||
return RangeIterator(fromInclusive, i => i < toExclusive, step); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generates a sequence of integral numbers within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="fromInclusive">
|
|||
/// The start index, inclusive.
|
|||
/// </param>
|
|||
/// <param name="toDelegate">
|
|||
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
|
|||
/// </param>
|
|||
/// <param name="step">
|
|||
/// The incremental step.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|||
/// </returns>
|
|||
public static IEnumerable<int> SteppedRange(int fromInclusive, Func<int, bool> toDelegate, int step) |
|||
{ |
|||
return RangeIterator(fromInclusive, toDelegate, step); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generates a sequence of integral numbers within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="fromInclusive">
|
|||
/// The start index, inclusive.
|
|||
/// </param>
|
|||
/// <param name="toDelegate">
|
|||
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
|
|||
/// </param>
|
|||
/// <param name="step">
|
|||
/// The incremental step.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|||
/// </returns>
|
|||
private static IEnumerable<int> RangeIterator(int fromInclusive, Func<int, bool> toDelegate, int step) |
|||
{ |
|||
int i = fromInclusive; |
|||
while (toDelegate(i)) |
|||
{ |
|||
yield return i; |
|||
i += step; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,192 +0,0 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Guard.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Provides methods to protect against invalid parameters.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
|
|||
[assembly: InternalsVisibleTo("ImageProcessorCore.Tests")] |
|||
namespace ImageProcessorCore |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods to protect against invalid parameters.
|
|||
/// </summary>
|
|||
[DebuggerStepThrough] |
|||
internal static class Guard |
|||
{ |
|||
/// <summary>
|
|||
/// Verifies, that the method parameter with specified object value is not null
|
|||
/// and throws an exception if it is found to be so.
|
|||
/// </summary>
|
|||
/// <param name="target">
|
|||
/// The target object, which cannot be null.
|
|||
/// </param>
|
|||
/// <param name="parameterName">
|
|||
/// The name of the parameter that is to be checked.
|
|||
/// </param>
|
|||
/// <param name="message">
|
|||
/// The error message, if any to add to the exception.
|
|||
/// </param>
|
|||
/// <exception cref="ArgumentNullException">
|
|||
/// <paramref name="target"/> is null
|
|||
/// </exception>
|
|||
public static void NotNull(object target, string parameterName, string message = "") |
|||
{ |
|||
if (target == null) |
|||
{ |
|||
if (string.IsNullOrWhiteSpace(message)) |
|||
{ |
|||
throw new ArgumentNullException(parameterName, message); |
|||
} |
|||
|
|||
throw new ArgumentNullException(parameterName); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Verifies, that the string method parameter with specified object value and message
|
|||
/// is not null, not empty and does not contain only blanks and throws an exception
|
|||
/// if the object is null.
|
|||
/// </summary>
|
|||
/// <param name="target">The target string, which should be checked against being null or empty.</param>
|
|||
/// <param name="parameterName">Name of the parameter.</param>
|
|||
/// <exception cref="ArgumentNullException">
|
|||
/// <paramref name="target"/> is null.
|
|||
/// </exception>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="target"/> is
|
|||
/// empty or contains only blanks.
|
|||
/// </exception>
|
|||
public static void NotNullOrEmpty(string target, string parameterName) |
|||
{ |
|||
if (target == null) |
|||
{ |
|||
throw new ArgumentNullException(parameterName); |
|||
} |
|||
|
|||
if (string.IsNullOrWhiteSpace(target)) |
|||
{ |
|||
throw new ArgumentException("Value cannot be null or empty and cannot contain only blanks.", parameterName); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Verifies that the specified value is less than a maximum value
|
|||
/// and throws an exception if it is not.
|
|||
/// </summary>
|
|||
/// <param name="value">The target value, which should be validated.</param>
|
|||
/// <param name="max">The maximum value.</param>
|
|||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="value"/> is greater than the maximum value.
|
|||
/// </exception>
|
|||
public static void MustBeLessThan<TValue>(TValue value, TValue max, string parameterName) |
|||
where TValue : IComparable<TValue> |
|||
{ |
|||
if (value.CompareTo(max) >= 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
parameterName, |
|||
$"Value must be less than {max}."); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Verifies that the specified value is less than or equal to a maximum value
|
|||
/// and throws an exception if it is not.
|
|||
/// </summary>
|
|||
/// <param name="value">The target value, which should be validated.</param>
|
|||
/// <param name="max">The maximum value.</param>
|
|||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="value"/> is greater than the maximum value.
|
|||
/// </exception>
|
|||
public static void MustBeLessThanOrEqualTo<TValue>(TValue value, TValue max, string parameterName) |
|||
where TValue : IComparable<TValue> |
|||
{ |
|||
if (value.CompareTo(max) > 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
parameterName, |
|||
$"Value must be less than or equal to {max}."); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Verifies that the specified value is greater than a minimum value
|
|||
/// and throws an exception if it is not.
|
|||
/// </summary>
|
|||
/// <param name="value">The target value, which should be validated.</param>
|
|||
/// <param name="min">The minimum value.</param>
|
|||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="value"/> is less than the minimum value.
|
|||
/// </exception>
|
|||
public static void MustBeGreaterThan<TValue>(TValue value, TValue min, string parameterName) |
|||
where TValue : IComparable<TValue> |
|||
{ |
|||
if (value.CompareTo(min) <= 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
parameterName, |
|||
$"Value must be greater than {min}."); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Verifies that the specified value is greater than or equal to a minimum value
|
|||
/// and throws an exception if it is not.
|
|||
/// </summary>
|
|||
/// <param name="value">The target value, which should be validated.</param>
|
|||
/// <param name="min">The minimum value.</param>
|
|||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="value"/> is less than the minimum value.
|
|||
/// </exception>
|
|||
public static void MustBeGreaterThanOrEqualTo<TValue>(TValue value, TValue min, string parameterName) |
|||
where TValue : IComparable<TValue> |
|||
{ |
|||
if (value.CompareTo(min) < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
parameterName, |
|||
$"Value must be greater than or equal to {min}."); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Verifies that the specified value is greater than or equal to a minimum value and less than
|
|||
/// or equal to a maximum value and throws an exception if it is not.
|
|||
/// </summary>
|
|||
/// <param name="value">The target value, which should be validated.</param>
|
|||
/// <param name="min">The minimum value.</param>
|
|||
/// <param name="max">The maximum value.</param>
|
|||
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
|
|||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="value"/> is less than the minimum value of greater than the maximum value.
|
|||
/// </exception>
|
|||
public static void MustBeBetweenOrEqualTo<TValue>(TValue value, TValue min, TValue max, string parameterName) |
|||
where TValue : IComparable<TValue> |
|||
{ |
|||
if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
parameterName, |
|||
$"Value must be greater than or equal to {min} and less than or equal to {max}."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,289 +0,0 @@ |
|||
// <copyright file="ImageMaths.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.Linq; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Provides common mathematical methods.
|
|||
/// </summary>
|
|||
internal static class ImageMaths |
|||
{ |
|||
/// <summary>
|
|||
/// Returns how many bits are required to store the specified number of colors.
|
|||
/// Performs a Log2() on the value.
|
|||
/// </summary>
|
|||
/// <param name="colors">The number of colors.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="int"/>
|
|||
/// </returns>
|
|||
public static int GetBitsNeededForColorDepth(int colors) |
|||
{ |
|||
return (int)Math.Ceiling(Math.Log(colors, 2)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Implementation of 1D Gaussian G(x) function
|
|||
/// </summary>
|
|||
/// <param name="x">The x provided to G(x).</param>
|
|||
/// <param name="sigma">The spread of the blur.</param>
|
|||
/// <returns>The Gaussian G(x)</returns>
|
|||
public static float Gaussian(float x, float sigma) |
|||
{ |
|||
const float Numerator = 1.0f; |
|||
float denominator = (float)(Math.Sqrt(2 * Math.PI) * sigma); |
|||
|
|||
float exponentNumerator = -x * x; |
|||
float exponentDenominator = (float)(2 * Math.Pow(sigma, 2)); |
|||
|
|||
float left = Numerator / denominator; |
|||
float right = (float)Math.Exp(exponentNumerator / exponentDenominator); |
|||
|
|||
return left * right; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the result of a B-C filter against the given value.
|
|||
/// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/>
|
|||
/// </summary>
|
|||
/// <param name="x">The value to process.</param>
|
|||
/// <param name="b">The B-Spline curve variable.</param>
|
|||
/// <param name="c">The Cardinal curve variable.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
public static float GetBcValue(float x, float b, float c) |
|||
{ |
|||
float temp; |
|||
|
|||
if (x < 0) |
|||
{ |
|||
x = -x; |
|||
} |
|||
|
|||
temp = x * x; |
|||
if (x < 1) |
|||
{ |
|||
x = ((12 - (9 * b) - (6 * c)) * (x * temp)) + ((-18 + (12 * b) + (6 * c)) * temp) + (6 - (2 * b)); |
|||
return x / 6; |
|||
} |
|||
|
|||
if (x < 2) |
|||
{ |
|||
x = ((-b - (6 * c)) * (x * temp)) + (((6 * b) + (30 * c)) * temp) + (((-12 * b) - (48 * c)) * x) + ((8 * b) + (24 * c)); |
|||
return x / 6; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the result of a sine cardinal function for the given value.
|
|||
/// </summary>
|
|||
/// <param name="x">The value to calculate the result for.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
public static float SinC(float x) |
|||
{ |
|||
const float Epsilon = .00001f; |
|||
|
|||
if (Math.Abs(x) > Epsilon) |
|||
{ |
|||
x *= (float)Math.PI; |
|||
return Clean((float)Math.Sin(x) / x); |
|||
} |
|||
|
|||
return 1.0f; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the given degrees converted to radians.
|
|||
/// </summary>
|
|||
/// <param name="degrees">The angle in degrees.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/> representing the degree as radians.
|
|||
/// </returns>
|
|||
public static float DegreesToRadians(float degrees) |
|||
{ |
|||
return degrees * (float)(Math.PI / 180); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the bounding <see cref="Rectangle"/> from the given points.
|
|||
/// </summary>
|
|||
/// <param name="topLeft">
|
|||
/// The <see cref="Point"/> designating the top left position.
|
|||
/// </param>
|
|||
/// <param name="bottomRight">
|
|||
/// The <see cref="Point"/> designating the bottom right position.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The bounding <see cref="Rectangle"/>.
|
|||
/// </returns>
|
|||
public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) |
|||
{ |
|||
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the bounding <see cref="Rectangle"/> from the given matrix.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The source rectangle.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Rectangle"/>.
|
|||
/// </returns>
|
|||
public static Rectangle GetBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) |
|||
{ |
|||
Vector2 leftTop = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); |
|||
Vector2 rightTop = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); |
|||
Vector2 leftBottom = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); |
|||
Vector2 rightBottom = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); |
|||
|
|||
Vector2[] allCorners = { leftTop, rightTop, leftBottom, rightBottom }; |
|||
float extentX = allCorners.Select(v => v.X).Max() - allCorners.Select(v => v.X).Min(); |
|||
float extentY = allCorners.Select(v => v.Y).Max() - allCorners.Select(v => v.Y).Min(); |
|||
return new Rectangle(0, 0, (int)extentX, (int)extentY); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Finds the bounding rectangle based on the first instance of any color component other
|
|||
/// than the given one.
|
|||
/// </summary>
|
|||
/// <param name="bitmap">The <see cref="Image"/> to search within.</param>
|
|||
/// <param name="componentValue">The color component value to remove.</param>
|
|||
/// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Rectangle"/>.
|
|||
/// </returns>
|
|||
public static Rectangle GetFilteredBoundingRectangle(ImageBase bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) |
|||
{ |
|||
const float Epsilon = .00001f; |
|||
int width = bitmap.Width; |
|||
int height = bitmap.Height; |
|||
Point topLeft = new Point(); |
|||
Point bottomRight = new Point(); |
|||
|
|||
Func<PixelAccessor, int, int, float, bool> delegateFunc; |
|||
|
|||
// Determine which channel to check against
|
|||
switch (channel) |
|||
{ |
|||
case RgbaComponent.R: |
|||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].R - b) > Epsilon; |
|||
break; |
|||
|
|||
case RgbaComponent.G: |
|||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].G - b) > Epsilon; |
|||
break; |
|||
|
|||
case RgbaComponent.A: |
|||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].A - b) > Epsilon; |
|||
break; |
|||
|
|||
default: |
|||
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].B - b) > Epsilon; |
|||
break; |
|||
} |
|||
|
|||
Func<PixelAccessor, int> getMinY = pixels => |
|||
{ |
|||
for (int y = 0; y < height; y++) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
if (delegateFunc(pixels, x, y, componentValue)) |
|||
{ |
|||
return y; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
}; |
|||
|
|||
Func<PixelAccessor, int> getMaxY = pixels => |
|||
{ |
|||
for (int y = height - 1; y > -1; y--) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
if (delegateFunc(pixels, x, y, componentValue)) |
|||
{ |
|||
return y; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return height; |
|||
}; |
|||
|
|||
Func<PixelAccessor, int> getMinX = pixels => |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
for (int y = 0; y < height; y++) |
|||
{ |
|||
if (delegateFunc(pixels, x, y, componentValue)) |
|||
{ |
|||
return x; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
}; |
|||
|
|||
Func<PixelAccessor, int> getMaxX = pixels => |
|||
{ |
|||
for (int x = width - 1; x > -1; x--) |
|||
{ |
|||
for (int y = 0; y < height; y++) |
|||
{ |
|||
if (delegateFunc(pixels, x, y, componentValue)) |
|||
{ |
|||
return x; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return height; |
|||
}; |
|||
|
|||
using (PixelAccessor bitmapPixels = bitmap.Lock()) |
|||
{ |
|||
topLeft.Y = getMinY(bitmapPixels); |
|||
topLeft.X = getMinX(bitmapPixels); |
|||
bottomRight.Y = (getMaxY(bitmapPixels) + 1).Clamp(0, height); |
|||
bottomRight.X = (getMaxX(bitmapPixels) + 1).Clamp(0, width); |
|||
} |
|||
|
|||
return GetBoundingRectangle(topLeft, bottomRight); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Ensures that any passed double is correctly rounded to zero
|
|||
/// </summary>
|
|||
/// <param name="x">The value to clean.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>
|
|||
/// </returns>.
|
|||
private static float Clean(float x) |
|||
{ |
|||
const float Epsilon = .00001f; |
|||
|
|||
if (Math.Abs(x) < Epsilon) |
|||
{ |
|||
return 0f; |
|||
} |
|||
|
|||
return x; |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="Alpha.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the alpha component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Alpha(this Image source, int percent, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Alpha(source, percent, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the alpha component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</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"/>.</returns>
|
|||
public static Image Alpha(this Image source, int percent, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
AlphaProcessor processor = new AlphaProcessor(percent); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
// <copyright file="BackgroundColor.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Combines the given image together with the current one by blending their pixels.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="color">The color to set as the background.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image BackgroundColor(this Image source, Color color, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
BackgroundColorProcessor processor = new BackgroundColorProcessor(color); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(source.Bounds, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <copyright file="BlackWhite.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies black and white toning to the image.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image BlackWhite(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return BlackWhite(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies black and white toning to the image.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image BlackWhite(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
BlackWhiteProcessor processor = new BlackWhiteProcessor(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
// <copyright file="Blend.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Combines the given image together with the current one by blending their pixels.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="image">
|
|||
/// The image to blend with the currently processing image.
|
|||
/// Disposal of this image is the responsibility of the developer.
|
|||
/// </param>
|
|||
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Blend(this Image source, ImageBase image, int percent = 50, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Blend(source, image, percent, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Combines the given image together with the current one by blending their pixels.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="image">
|
|||
/// The image to blend with the currently processing image.
|
|||
/// Disposal of this image is the responsibility of the developer.
|
|||
/// </param>
|
|||
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</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"/>.</returns>
|
|||
public static Image Blend(this Image source, ImageBase image, int percent, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
BlendProcessor processor = new BlendProcessor(image, percent); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="BoxBlur.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a box blur to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image BoxBlur(this Image source, int radius = 7, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return BoxBlur(source, radius, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies a box blur to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="radius">The 'radius' value representing the size of the area to sample.</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"/>.</returns>
|
|||
public static Image BoxBlur(this Image source, int radius, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
BoxBlurProcessor processor = new BoxBlurProcessor(radius); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="Brightness.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the brightness component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Brightness(this Image source, int amount, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Brightness(source, amount, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the brightness component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</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"/>.</returns>
|
|||
public static Image Brightness(this Image source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
BrightnessProcessor processor = new BrightnessProcessor(amount); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,88 +0,0 @@ |
|||
// <copyright file="ColorBlindness.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the given colorblindness simulator to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image ColorBlindness(this Image source, ColorBlindness colorBlindness, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return ColorBlindness(source, colorBlindness, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the given colorblindness simulator to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="colorBlindness">The type of color blindness simulator to apply.</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"/>.</returns>
|
|||
public static Image ColorBlindness(this Image source, ColorBlindness colorBlindness, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
IImageProcessor processor; |
|||
|
|||
switch (colorBlindness) |
|||
{ |
|||
case ImageProcessorCore.ColorBlindness.Achromatomaly: |
|||
processor = new AchromatomalyProcessor(); |
|||
break; |
|||
|
|||
case ImageProcessorCore.ColorBlindness.Achromatopsia: |
|||
processor = new AchromatopsiaProcessor(); |
|||
break; |
|||
|
|||
case ImageProcessorCore.ColorBlindness.Deuteranomaly: |
|||
processor = new DeuteranomalyProcessor(); |
|||
break; |
|||
|
|||
case ImageProcessorCore.ColorBlindness.Deuteranopia: |
|||
processor = new DeuteranopiaProcessor(); |
|||
break; |
|||
|
|||
case ImageProcessorCore.ColorBlindness.Protanomaly: |
|||
processor = new ProtanomalyProcessor(); |
|||
break; |
|||
|
|||
case ImageProcessorCore.ColorBlindness.Protanopia: |
|||
processor = new ProtanopiaProcessor(); |
|||
break; |
|||
|
|||
case ImageProcessorCore.ColorBlindness.Tritanomaly: |
|||
processor = new TritanomalyProcessor(); |
|||
break; |
|||
|
|||
default: |
|||
processor = new TritanopiaProcessor(); |
|||
break; |
|||
} |
|||
|
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="Contrast.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the contrast component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Contrast(this Image source, int amount, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Contrast(source, amount, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the contrast component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</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"/>.</returns>
|
|||
public static Image Contrast(this Image source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
ContrastProcessor processor = new ContrastProcessor(amount); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,63 +0,0 @@ |
|||
// <copyright file="DetectEdges.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter
|
|||
/// operating in greyscale mode.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image DetectEdges(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return DetectEdges(source, source.Bounds, new SobelProcessor { Greyscale = true }, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Detects any edges within the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="filter">The filter for detecting edges.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image DetectEdges(this Image source, IEdgeDetectorFilter filter, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return DetectEdges(source, source.Bounds, filter, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Detects any edges within the image.
|
|||
/// </summary>
|
|||
/// <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="filter">The filter for detecting edges.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image DetectEdges(this Image source, Rectangle rectangle, IEdgeDetectorFilter filter, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
filter.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, filter); |
|||
} |
|||
finally |
|||
{ |
|||
filter.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
// <copyright file="Greyscale.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies greyscale toning to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="mode">The formula to apply to perform the operation.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Greyscale(this Image source, GreyscaleMode mode = GreyscaleMode.Bt709, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Greyscale(source, source.Bounds, mode, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies greyscale toning to the image.
|
|||
/// </summary>
|
|||
/// <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="mode">The formula to apply to perform the operation.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Greyscale(this Image source, Rectangle rectangle, GreyscaleMode mode = GreyscaleMode.Bt709, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
IImageProcessor processor = mode == GreyscaleMode.Bt709 |
|||
? (IImageProcessor)new GreyscaleBt709Processor() |
|||
: new GreyscaleBt601Processor(); |
|||
|
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="GuassianBlur.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a Guassian blur to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image GuassianBlur(this Image source, float sigma = 3f, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return GuassianBlur(source, sigma, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies a Guassian blur to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</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"/>.</returns>
|
|||
public static Image GuassianBlur(this Image source, float sigma, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
GuassianBlurProcessor processor = new GuassianBlurProcessor(sigma); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="GuassianSharpen.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a Guassian sharpening filter to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image GuassianSharpen(this Image source, float sigma = 3f, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return GuassianSharpen(source, sigma, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies a Guassian sharpening filter to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</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"/>.</returns>
|
|||
public static Image GuassianSharpen(this Image source, float sigma, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
GuassianSharpenProcessor processor = new GuassianSharpenProcessor(sigma); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="Hue.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the hue component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="degrees">The angle in degrees to adjust the image.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Hue(this Image source, float degrees, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Hue(source, degrees, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the hue component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="degrees">The angle in degrees to adjust the image.</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"/>.</returns>
|
|||
public static Image Hue(this Image source, float degrees, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
HueProcessor processor = new HueProcessor(degrees); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <copyright file="Invert.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Inverts the colors of the image.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Invert(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Invert(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Inverts the colors of the image.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Invert(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
InvertProcessor processor = new InvertProcessor(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <copyright file="Kodachrome.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Kodachrome camera effect.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Kodachrome(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Kodachrome(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Kodachrome camera effect.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Kodachrome(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
KodachromeProcessor processor = new KodachromeProcessor(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Lomograph camera effect.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Lomograph(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Lomograph(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Lomograph camera effect.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Lomograph(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
LomographProcessor processor = new LomographProcessor(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,53 +0,0 @@ |
|||
// <copyright file="ColorBlindness.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerates the various types of color blindness.
|
|||
/// </summary>
|
|||
public enum ColorBlindness |
|||
{ |
|||
/// <summary>
|
|||
/// Partial color desensitivity.
|
|||
/// </summary>
|
|||
Achromatomaly, |
|||
|
|||
/// <summary>
|
|||
/// Complete color desensitivity (Monochrome)
|
|||
/// </summary>
|
|||
Achromatopsia, |
|||
|
|||
/// <summary>
|
|||
/// Green weak
|
|||
/// </summary>
|
|||
Deuteranomaly, |
|||
|
|||
/// <summary>
|
|||
/// Green blind
|
|||
/// </summary>
|
|||
Deuteranopia, |
|||
|
|||
/// <summary>
|
|||
/// Red weak
|
|||
/// </summary>
|
|||
Protanomaly, |
|||
|
|||
/// <summary>
|
|||
/// Red blind
|
|||
/// </summary>
|
|||
Protanopia, |
|||
|
|||
/// <summary>
|
|||
/// Blue weak
|
|||
/// </summary>
|
|||
Tritanomaly, |
|||
|
|||
/// <summary>
|
|||
/// Blue blind
|
|||
/// </summary>
|
|||
Tritanopia |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="Pixelate.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Pixelates and image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="size">The size of the pixels.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Pixelate(this Image source, int size = 4, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Pixelate(source, size, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pixelates and image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="size">The size of the pixels.</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"/>.</returns>
|
|||
public static Image Pixelate(this Image source, int size, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
PixelateProcessor processor = new PixelateProcessor(size); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Polaroid camera effect.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Polaroid(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Polaroid(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the colors of the image recreating an old Polaroid camera effect.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Polaroid(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
PolaroidProcessor processor = new PolaroidProcessor(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,69 +0,0 @@ |
|||
// <copyright file="AlphaProcessor.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>
|
|||
/// An <see cref="IImageProcessor"/> to change the Alpha of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
public class AlphaProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AlphaProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="percent">The percentage to adjust the opacity of the image. Must be between 0 and 100.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="percent"/> is less than 0 or is greater than 100.
|
|||
/// </exception>
|
|||
public AlphaProcessor(int percent) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(percent, 0, 100, nameof(percent)); |
|||
this.Value = percent; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the alpha value.
|
|||
/// </summary>
|
|||
public int Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
float alpha = this.Value / 100f; |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Vector4 alphaVector = new Vector4(1, 1, 1, alpha); |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Vector4 color = Color.ToNonPremultiplied(sourcePixels[x, y]).ToVector4(); |
|||
color *= alphaVector; |
|||
targetPixels[x, y] = Color.FromNonPremultiplied(new Color(color)); |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,78 +0,0 @@ |
|||
// <copyright file="BackgroundColorProcessor.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.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Sets the background color of the image.
|
|||
/// </summary>
|
|||
public class BackgroundColorProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.001f; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BackgroundColorProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="color">The <see cref="Color"/> to set the background color to.</param>
|
|||
public BackgroundColorProcessor(Color color) |
|||
{ |
|||
this.Value = Color.FromNonPremultiplied(color); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the background color value.
|
|||
/// </summary>
|
|||
public Color Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Color backgroundColor = this.Value; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Color color = sourcePixels[x, y]; |
|||
float a = color.A; |
|||
|
|||
if (a < 1 && a > 0) |
|||
{ |
|||
color = Color.Lerp(color, backgroundColor, .5f); |
|||
} |
|||
|
|||
if (Math.Abs(a) < Epsilon) |
|||
{ |
|||
color = backgroundColor; |
|||
} |
|||
|
|||
targetPixels[x, y] = color; |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,86 +0,0 @@ |
|||
// <copyright file="ThresholdProcessor.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.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// An <see cref="IImageProcessor"/> to perform binary threshold filtering against an
|
|||
/// <see cref="Image"/>. The image will be converted to greyscale before thresholding
|
|||
/// occurs.
|
|||
/// </summary>
|
|||
public class ThresholdProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ThresholdProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="threshold"/> is less than 0 or is greater than 1.
|
|||
/// </exception>
|
|||
public ThresholdProcessor(float threshold) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold)); |
|||
this.Value = threshold; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the threshold value.
|
|||
/// </summary>
|
|||
public float Value { get; } |
|||
|
|||
/// <summary>
|
|||
/// The color to use for pixels that are above the threshold.
|
|||
/// </summary>
|
|||
public Color UpperColor => Color.White; |
|||
|
|||
/// <summary>
|
|||
/// The color to use for pixels that fall below the threshold.
|
|||
/// </summary>
|
|||
public Color LowerColor => Color.Black; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
new GreyscaleBt709Processor().Apply(source, source, sourceRectangle); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
float threshold = this.Value; |
|||
Color upper = this.UpperColor; |
|||
Color lower = this.LowerColor; |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Color color = sourcePixels[x, y]; |
|||
|
|||
// Any channel will do since it's greyscale.
|
|||
targetPixels[x, y] = color.B >= threshold ? upper : lower; |
|||
} |
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,86 +0,0 @@ |
|||
// <copyright file="BlendProcessor.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.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Combines two images together by blending the pixels.
|
|||
/// </summary>
|
|||
public class BlendProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The image to blend.
|
|||
/// </summary>
|
|||
private readonly ImageBase blend; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BlendProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="image">
|
|||
/// The image to blend with the currently processing image.
|
|||
/// Disposal of this image is the responsibility of the developer.
|
|||
/// </param>
|
|||
/// <param name="alpha">The opacity of the image to blend. Between 0 and 100.</param>
|
|||
public BlendProcessor(ImageBase image, int alpha = 100) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(alpha, 0, 100, nameof(alpha)); |
|||
this.blend = image; |
|||
this.Value = alpha; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the alpha percentage value.
|
|||
/// </summary>
|
|||
public int Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Rectangle bounds = this.blend.Bounds; |
|||
float alpha = this.Value / 100f; |
|||
|
|||
using (PixelAccessor toBlendPixels = this.blend.Lock()) |
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Color color = sourcePixels[x, y]; |
|||
|
|||
if (bounds.Contains(x, y)) |
|||
{ |
|||
Color blendedColor = toBlendPixels[x, y]; |
|||
|
|||
if (blendedColor.A > 0) |
|||
{ |
|||
// Lerping colors is dependent on the alpha of the blended color
|
|||
float alphaFactor = alpha > 0 ? alpha : blendedColor.A; |
|||
color = Color.Lerp(color, blendedColor, alphaFactor); |
|||
} |
|||
} |
|||
|
|||
targetPixels[x, y] = color; |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,69 +0,0 @@ |
|||
// <copyright file="BrightnessProcessor.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>
|
|||
/// An <see cref="IImageProcessor"/> to change the brightness of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
public class BrightnessProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BrightnessProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="brightness">The new brightness of the image. Must be between -100 and 100.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="brightness"/> is less than -100 or is greater than 100.
|
|||
/// </exception>
|
|||
public BrightnessProcessor(int brightness) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(brightness, -100, 100, nameof(brightness)); |
|||
this.Value = brightness; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the brightness value.
|
|||
/// </summary>
|
|||
public int Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
float brightness = this.Value / 100f; |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Color color = Color.Expand(sourcePixels[x, y]); |
|||
|
|||
Vector3 vector3 = color.ToVector3(); |
|||
vector3 += new Vector3(brightness); |
|||
|
|||
targetPixels[x, y] = Color.Compress(new Color(vector3, color.A)); |
|||
} |
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// <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>
|
|||
public class BlackWhiteProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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, |
|||
}; |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// <copyright file="AchromatomalyProcessor.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 Achromatomaly (Color desensitivity) color blindness.
|
|||
/// </summary>
|
|||
public class AchromatomalyProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = .618f, |
|||
M12 = .163f, |
|||
M13 = .163f, |
|||
M21 = .320f, |
|||
M22 = .775f, |
|||
M23 = .320f, |
|||
M31 = .062f, |
|||
M32 = .062f, |
|||
M33 = .516f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// <copyright file="AchromatopsiaProcessor.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 Achromatopsia (Monochrome) color blindness.
|
|||
/// </summary>
|
|||
public class AchromatopsiaProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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 |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="DeuteranomalyProcessor.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 Deuteranomaly (Green-Weak) color blindness.
|
|||
/// </summary>
|
|||
public class DeuteranomalyProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.8f, |
|||
M12 = 0.258f, |
|||
M21 = 0.2f, |
|||
M22 = 0.742f, |
|||
M23 = 0.142f, |
|||
M33 = 0.858f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="DeuteranopiaProcessor.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 Deuteranopia (Green-Blind) color blindness.
|
|||
/// </summary>
|
|||
public class DeuteranopiaProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.625f, |
|||
M12 = 0.7f, |
|||
M21 = 0.375f, |
|||
M22 = 0.3f, |
|||
M23 = 0.3f, |
|||
M33 = 0.7f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="ProtanomalyProcessor.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 Protanopia (Red-Weak) color blindness.
|
|||
/// </summary>
|
|||
public class ProtanomalyProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.817f, |
|||
M12 = 0.333f, |
|||
M21 = 0.183f, |
|||
M22 = 0.667f, |
|||
M23 = 0.125f, |
|||
M33 = 0.875f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="ProtanopiaProcessor.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 Protanopia (Red-Blind) color blindness.
|
|||
/// </summary>
|
|||
public class ProtanopiaProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.567f, |
|||
M12 = 0.558f, |
|||
M21 = 0.433f, |
|||
M22 = 0.442f, |
|||
M23 = 0.242f, |
|||
M33 = 0.758f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,4 +0,0 @@ |
|||
Color blindness matrices adapted from and tested against: |
|||
|
|||
http://web.archive.org/web/20090413045433/http://nofunc.org/Color_Matrix_Library |
|||
http://www.color-blindness.com/coblis-color-blindness-simulator/ |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="TritanomalyProcessor.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 Tritanomaly (Blue-Weak) color blindness.
|
|||
/// </summary>
|
|||
public class TritanomalyProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.967f, |
|||
M21 = 0.33f, |
|||
M22 = 0.733f, |
|||
M23 = 0.183f, |
|||
M32 = 0.267f, |
|||
M33 = 0.817f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
// <copyright file="TritanopiaProcessor.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 Tritanopia (Blue-Blind) color blindness.
|
|||
/// </summary>
|
|||
public class TritanopiaProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = 0.95f, |
|||
M21 = 0.05f, |
|||
M22 = 0.433f, |
|||
M23 = 0.475f, |
|||
M32 = 0.567f, |
|||
M33 = 0.525f |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,68 +0,0 @@ |
|||
// <copyright file="ColorMatrixFilter.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; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// The color matrix filter.
|
|||
/// </summary>
|
|||
public abstract class ColorMatrixFilter : ImageProcessor, IColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public abstract Matrix4x4 Matrix { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public virtual bool Compand => true; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Matrix4x4 matrix = this.Matrix; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
targetPixels[x, y] = this.ApplyMatrix(sourcePixels[x, y], matrix); |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the color matrix against the given color.
|
|||
/// </summary>
|
|||
/// <param name="color">The source color.</param>
|
|||
/// <param name="matrix">The matrix.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>.
|
|||
/// </returns>
|
|||
private Color ApplyMatrix(Color color, Matrix4x4 matrix) |
|||
{ |
|||
bool compand = this.Compand; |
|||
|
|||
if (compand) |
|||
{ |
|||
color = Color.Expand(color); |
|||
} |
|||
|
|||
Vector3 transformed = Vector3.Transform(color.ToVector3(), matrix); |
|||
return compand ? Color.Compress(new Color(transformed, color.A)) : new Color(transformed, color.A); |
|||
} |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <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>
|
|||
public class GreyscaleBt601Processor : ColorMatrixFilter |
|||
{ |
|||
/// <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 |
|||
}; |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <copyright file="GreyscaleBt709Processor.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.709 <see href="https://en.wikipedia.org/wiki/Rec._709#Luma_coefficients"/>.
|
|||
/// </summary>
|
|||
public class GreyscaleBt709Processor : ColorMatrixFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4() |
|||
{ |
|||
M11 = .2126f, |
|||
M12 = .2126f, |
|||
M13 = .2126f, |
|||
M21 = .7152f, |
|||
M22 = .7152f, |
|||
M23 = .7152f, |
|||
M31 = .0722f, |
|||
M32 = .0722f, |
|||
M33 = .0722f |
|||
}; |
|||
} |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
// <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 |
|||
} |
|||
} |
|||
@ -1,81 +0,0 @@ |
|||
// <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; |
|||
|
|||
public class HueProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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 target, ImageBase 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; |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
// <copyright file="IColorMatrixFilter.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>
|
|||
/// Encapsulates properties and methods for creating processors that utilize a matrix to
|
|||
/// alter the image pixels.
|
|||
/// </summary>
|
|||
public interface IColorMatrixFilter : IImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the <see cref="Matrix4x4"/> used to alter the image.
|
|||
/// </summary>
|
|||
Matrix4x4 Matrix { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether to compress
|
|||
/// or expand individual pixel colors the value on processing.
|
|||
/// </summary>
|
|||
bool Compand { get; } |
|||
} |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
// <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>
|
|||
public class KodachromeProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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 |
|||
}; |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// <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>
|
|||
public class LomographProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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 target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
new VignetteProcessor { Color = new Color(0, 10 / 255f, 0) }.Apply(target, target, targetRectangle); |
|||
} |
|||
} |
|||
} |
|||
@ -1,45 +0,0 @@ |
|||
// <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>
|
|||
public class PolaroidProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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 target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
new VignetteProcessor { Color = new Color(102 / 255f, 34 / 255f, 0) }.Apply(target, target, targetRectangle); |
|||
new GlowProcessor |
|||
{ |
|||
Color = new Color(1, 153 / 255f, 102 / 255f, .7f), |
|||
RadiusX = target.Width / 4f, |
|||
RadiusY = target.Width / 4f |
|||
} |
|||
.Apply(target, target, targetRectangle); |
|||
} |
|||
} |
|||
} |
|||
@ -1,75 +0,0 @@ |
|||
// <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; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// An <see cref="IImageProcessor"/> to change the saturation of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
public class SaturationProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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 target, ImageBase 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; |
|||
} |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
// <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>
|
|||
public class SepiaProcessor : ColorMatrixFilter |
|||
{ |
|||
/// <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; |
|||
} |
|||
} |
|||
@ -1,70 +0,0 @@ |
|||
// <copyright file="ContrastProcessor.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>
|
|||
/// An <see cref="IImageProcessor"/> to change the contrast of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
public class ContrastProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ContrastProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="contrast">The new contrast of the image. Must be between -100 and 100.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="contrast"/> is less than -100 or is greater than 100.
|
|||
/// </exception>
|
|||
public ContrastProcessor(int contrast) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(contrast, -100, 100, nameof(contrast)); |
|||
this.Value = contrast; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the contrast value.
|
|||
/// </summary>
|
|||
public int Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
float contrast = (100f + this.Value) / 100f; |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Vector4 contrastVector = new Vector4(contrast, contrast, contrast, 1); |
|||
Vector4 shiftVector = new Vector4(.5f, .5f, .5f, 1); |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Vector4 color = Color.Expand(sourcePixels[x, y]).ToVector4(); |
|||
color -= shiftVector; |
|||
color *= contrastVector; |
|||
color += shiftVector; |
|||
targetPixels[x, y] = Color.Compress(new Color(color)); |
|||
} |
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,103 +0,0 @@ |
|||
// <copyright file="BoxBlurProcessor.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>
|
|||
/// Applies a Box blur filter to the image.
|
|||
/// </summary>
|
|||
public class BoxBlurProcessor : Convolution2PassFilter |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum size of the kernal in either direction.
|
|||
/// </summary>
|
|||
private readonly int kernelSize; |
|||
|
|||
/// <summary>
|
|||
/// The vertical kernel
|
|||
/// </summary>
|
|||
private float[,] kernelY; |
|||
|
|||
/// <summary>
|
|||
/// The horizontal kernel
|
|||
/// </summary>
|
|||
private float[,] kernelX; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianBlurProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="radius">
|
|||
/// The 'radius' value representing the size of the area to sample.
|
|||
/// </param>
|
|||
public BoxBlurProcessor(int radius = 7) |
|||
{ |
|||
this.kernelSize = (radius * 2) + 1; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => this.kernelX; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => this.kernelY; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
if (this.kernelY == null) |
|||
{ |
|||
this.kernelY = this.CreateBoxKernel(false); |
|||
} |
|||
|
|||
if (this.kernelX == null) |
|||
{ |
|||
this.kernelX = this.CreateBoxKernel(true); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a 1 dimensional Box kernel.
|
|||
/// </summary>
|
|||
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
|
|||
/// <returns>The <see cref="T:float[,]"/></returns>
|
|||
private float[,] CreateBoxKernel(bool horizontal) |
|||
{ |
|||
int size = this.kernelSize; |
|||
float[,] kernel = horizontal ? new float[1, size] : new float[size, 1]; |
|||
float sum = 0.0f; |
|||
|
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
float x = 1; |
|||
sum += x; |
|||
if (horizontal) |
|||
{ |
|||
kernel[0, i] = x; |
|||
} |
|||
else |
|||
{ |
|||
kernel[i, 0] = x; |
|||
} |
|||
} |
|||
|
|||
// Normalise kernel so that the sum of all weights equals 1
|
|||
if (horizontal) |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[0, i] = kernel[0, i] / sum; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[i, 0] = kernel[i, 0] / sum; |
|||
} |
|||
} |
|||
|
|||
return kernel; |
|||
} |
|||
} |
|||
} |
|||
@ -1,113 +0,0 @@ |
|||
// <copyright file="Convolution2DFilter.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.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Defines a filter that uses two one-dimensional matrices to perform convolution against an image.
|
|||
/// </summary>
|
|||
public abstract class Convolution2DFilter : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the horizontal gradient operator.
|
|||
/// </summary>
|
|||
public abstract float[,] KernelX { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the vertical gradient operator.
|
|||
/// </summary>
|
|||
public abstract float[,] KernelY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
float[,] kernelX = this.KernelX; |
|||
float[,] kernelY = this.KernelY; |
|||
int kernelYHeight = kernelY.GetLength(0); |
|||
int kernelYWidth = kernelY.GetLength(1); |
|||
int kernelXHeight = kernelX.GetLength(0); |
|||
int kernelXWidth = kernelX.GetLength(1); |
|||
int radiusY = kernelYHeight >> 1; |
|||
int radiusX = kernelXWidth >> 1; |
|||
|
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
int maxY = sourceBottom - 1; |
|||
int maxX = endX - 1; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
float rX = 0; |
|||
float gX = 0; |
|||
float bX = 0; |
|||
float rY = 0; |
|||
float gY = 0; |
|||
float bY = 0; |
|||
|
|||
// Apply each matrix multiplier to the color components for each pixel.
|
|||
for (int fy = 0; fy < kernelYHeight; fy++) |
|||
{ |
|||
int fyr = fy - radiusY; |
|||
int offsetY = y + fyr; |
|||
|
|||
offsetY = offsetY.Clamp(0, maxY); |
|||
|
|||
for (int fx = 0; fx < kernelXWidth; fx++) |
|||
{ |
|||
int fxr = fx - radiusX; |
|||
int offsetX = x + fxr; |
|||
|
|||
offsetX = offsetX.Clamp(0, maxX); |
|||
|
|||
Color currentColor = sourcePixels[offsetX, offsetY]; |
|||
float r = currentColor.R; |
|||
float g = currentColor.G; |
|||
float b = currentColor.B; |
|||
|
|||
if (fy < kernelXHeight) |
|||
{ |
|||
rX += kernelX[fy, fx] * r; |
|||
gX += kernelX[fy, fx] * g; |
|||
bX += kernelX[fy, fx] * b; |
|||
} |
|||
|
|||
if (fx < kernelYWidth) |
|||
{ |
|||
rY += kernelY[fy, fx] * r; |
|||
gY += kernelY[fy, fx] * g; |
|||
bY += kernelY[fy, fx] * b; |
|||
} |
|||
} |
|||
} |
|||
|
|||
float red = (float)Math.Sqrt((rX * rX) + (rY * rY)); |
|||
float green = (float)Math.Sqrt((gX * gX) + (gY * gY)); |
|||
float blue = (float)Math.Sqrt((bX * bX) + (bY * bY)); |
|||
|
|||
Color targetColor = targetPixels[x, y]; |
|||
targetPixels[x, y] = new Color(red, green, blue, targetColor.A); |
|||
} |
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,113 +0,0 @@ |
|||
// <copyright file="Convolution2PassFilter.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.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Defines a filter that uses two one-dimensional matrices to perform two-pass convolution against an image.
|
|||
/// </summary>
|
|||
public abstract class Convolution2PassFilter : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the horizontal gradient operator.
|
|||
/// </summary>
|
|||
public abstract float[,] KernelX { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the vertical gradient operator.
|
|||
/// </summary>
|
|||
public abstract float[,] KernelY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply( |
|||
ImageBase target, |
|||
ImageBase source, |
|||
Rectangle targetRectangle, |
|||
Rectangle sourceRectangle, |
|||
int startY, |
|||
int endY) |
|||
{ |
|||
float[,] kernelX = this.KernelX; |
|||
float[,] kernelY = this.KernelY; |
|||
|
|||
ImageBase firstPass = new Image(source.Width, source.Height); |
|||
this.ApplyConvolution(firstPass, source, sourceRectangle, startY, endY, kernelX); |
|||
this.ApplyConvolution(target, firstPass, sourceRectangle, startY, endY, kernelY); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the process to the specified portion of the specified <see cref="ImageBase"/> at the specified location
|
|||
/// and with the specified size.
|
|||
/// </summary>
|
|||
/// <param name="target">Target image to apply the process to.</param>
|
|||
/// <param name="source">The source image. Cannot be null.</param>
|
|||
/// <param name="sourceRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|||
/// </param>
|
|||
/// <param name="startY">The index of the row within the source image to start processing.</param>
|
|||
/// <param name="endY">The index of the row within the source image to end processing.</param>
|
|||
/// <param name="kernel">The kernel operator.</param>
|
|||
private void ApplyConvolution( |
|||
ImageBase target, |
|||
ImageBase source, |
|||
Rectangle sourceRectangle, |
|||
int startY, |
|||
int endY, |
|||
float[,] kernel) |
|||
{ |
|||
int kernelHeight = kernel.GetLength(0); |
|||
int kernelWidth = kernel.GetLength(1); |
|||
int radiusY = kernelHeight >> 1; |
|||
int radiusX = kernelWidth >> 1; |
|||
|
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
int maxY = sourceBottom - 1; |
|||
int maxX = endX - 1; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Color destination = new Color(); |
|||
|
|||
// Apply each matrix multiplier to the color components for each pixel.
|
|||
for (int fy = 0; fy < kernelHeight; fy++) |
|||
{ |
|||
int fyr = fy - radiusY; |
|||
int offsetY = y + fyr; |
|||
|
|||
offsetY = offsetY.Clamp(0, maxY); |
|||
|
|||
for (int fx = 0; fx < kernelWidth; fx++) |
|||
{ |
|||
int fxr = fx - radiusX; |
|||
int offsetX = x + fxr; |
|||
|
|||
offsetX = offsetX.Clamp(0, maxX); |
|||
|
|||
Color currentColor = sourcePixels[offsetX, offsetY]; |
|||
destination += kernel[fy, fx] * currentColor; |
|||
} |
|||
} |
|||
|
|||
targetPixels[x, y] = destination; |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,88 +0,0 @@ |
|||
// <copyright file="ConvolutionFilter.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.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Defines a filter that uses a 2 dimensional matrix to perform convolution against an image.
|
|||
/// </summary>
|
|||
public abstract class ConvolutionFilter : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the 2d gradient operator.
|
|||
/// </summary>
|
|||
public abstract float[,] KernelXY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
float[,] kernelX = this.KernelXY; |
|||
int kernelLength = kernelX.GetLength(0); |
|||
int radius = kernelLength >> 1; |
|||
|
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
int maxY = sourceBottom - 1; |
|||
int maxX = endX - 1; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
float rX = 0; |
|||
float gX = 0; |
|||
float bX = 0; |
|||
|
|||
// Apply each matrix multiplier to the color components for each pixel.
|
|||
for (int fy = 0; fy < kernelLength; fy++) |
|||
{ |
|||
int fyr = fy - radius; |
|||
int offsetY = y + fyr; |
|||
|
|||
offsetY = offsetY.Clamp(0, maxY); |
|||
|
|||
for (int fx = 0; fx < kernelLength; fx++) |
|||
{ |
|||
int fxr = fx - radius; |
|||
int offsetX = x + fxr; |
|||
|
|||
offsetX = offsetX.Clamp(0, maxX); |
|||
|
|||
Color currentColor = sourcePixels[offsetX, offsetY]; |
|||
float r = currentColor.R; |
|||
float g = currentColor.G; |
|||
float b = currentColor.B; |
|||
|
|||
rX += kernelX[fy, fx] * r; |
|||
gX += kernelX[fy, fx] * g; |
|||
bX += kernelX[fy, fx] * b; |
|||
} |
|||
} |
|||
|
|||
float red = rX; |
|||
float green = gX; |
|||
float blue = bX; |
|||
|
|||
targetPixels[x, y] = new Color(red, green, blue); |
|||
} |
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
// <copyright file="EdgeDetector2DFilter.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>
|
|||
/// Defines a filter that detects edges within an image using two
|
|||
/// one-dimensional matrices.
|
|||
/// </summary>
|
|||
public abstract class EdgeDetector2DFilter : Convolution2DFilter, IEdgeDetectorFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public bool Greyscale { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
if (this.Greyscale) |
|||
{ |
|||
new GreyscaleBt709Processor().Apply(source, source, sourceRectangle); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
// <copyright file="EdgeDetectorFilter.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>
|
|||
/// Defines a filter that detects edges within an image using a single
|
|||
/// two dimensional matrix.
|
|||
/// </summary>
|
|||
public abstract class EdgeDetectorFilter : ConvolutionFilter, IEdgeDetectorFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public bool Greyscale { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
if (this.Greyscale) |
|||
{ |
|||
new GreyscaleBt709Processor().Apply(source, source, sourceRectangle); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// <copyright file="IEdgeDetectorFilter.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 properties and methods allowing the detection of edges within an image.
|
|||
/// </summary>
|
|||
public interface IEdgeDetectorFilter : IImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether to convert the
|
|||
/// image to greyscale before performing edge detection.
|
|||
/// </summary>
|
|||
bool Greyscale { get; set; } |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <copyright file="KayyaliProcessor.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>
|
|||
/// The Kayyali operator filter.
|
|||
/// <see href="http://edgedetection.webs.com/"/>
|
|||
/// </summary>
|
|||
public class KayyaliProcessor : EdgeDetector2DFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => new float[,] |
|||
{ |
|||
{ 6, 0, -6 }, |
|||
{ 0, 0, 0 }, |
|||
{ -6, 0, 6 } |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => new float[,] |
|||
{ |
|||
{ -6, 0, 6 }, |
|||
{ 0, 0, 0 }, |
|||
{ 6, 0, -6 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <copyright file="KirschProcessor.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>
|
|||
/// The Kirsch operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>
|
|||
/// </summary>
|
|||
public class KirschProcessor : EdgeDetector2DFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => new float[,] |
|||
{ |
|||
{ 5, 5, 5 }, |
|||
{ -3, 0, -3 }, |
|||
{ -3, -3, -3 } |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => new float[,] |
|||
{ |
|||
{ 5, -3, -3 }, |
|||
{ 5, 0, -3 }, |
|||
{ 5, -3, -3 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
// <copyright file="Laplacian3X3Processor.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>
|
|||
/// The Laplacian 3 x 3 operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
|
|||
/// </summary>
|
|||
public class Laplacian3X3Processor : EdgeDetectorFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelXY => new float[,] |
|||
{ |
|||
{ -1, -1, -1 }, |
|||
{ -1, 8, -1 }, |
|||
{ -1, -1, -1 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
// <copyright file="Laplacian5X5Processor.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>
|
|||
/// The Laplacian 5 x 5 operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
|
|||
/// </summary>
|
|||
public class Laplacian5X5Processor : EdgeDetectorFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelXY => new float[,] |
|||
{ |
|||
{ -1, -1, -1, -1, -1 }, |
|||
{ -1, -1, -1, -1, -1 }, |
|||
{ -1, -1, 24, -1, -1 }, |
|||
{ -1, -1, -1, -1, -1 }, |
|||
{ -1, -1, -1, -1, -1 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
// <copyright file="LaplacianOfGaussianProcessor.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>
|
|||
/// The Laplacian of Gaussian operator filter.
|
|||
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>
|
|||
/// </summary>
|
|||
public class LaplacianOfGaussianProcessor : EdgeDetectorFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelXY => new float[,] |
|||
{ |
|||
{ 0, 0, -1, 0, 0 }, |
|||
{ 0, -1, -2, -1, 0 }, |
|||
{ -1, -2, 16, -2, -1 }, |
|||
{ 0, -1, -2, -1, 0 }, |
|||
{ 0, 0, -1, 0, 0 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <copyright file="PrewittProcessor.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>
|
|||
/// The Prewitt operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>
|
|||
/// </summary>
|
|||
public class PrewittProcessor : EdgeDetector2DFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => new float[,] |
|||
{ |
|||
{ -1, 0, 1 }, |
|||
{ -1, 0, 1 }, |
|||
{ -1, 0, 1 } |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => new float[,] |
|||
{ |
|||
{ 1, 1, 1 }, |
|||
{ 0, 0, 0 }, |
|||
{ -1, -1, -1 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
// <copyright file="RobertsCrossProcessor.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>
|
|||
/// The Roberts Cross operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>
|
|||
/// </summary>
|
|||
public class RobertsCrossProcessor : EdgeDetector2DFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => new float[,] |
|||
{ |
|||
{ 1, 0 }, |
|||
{ 0, -1 } |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => new float[,] |
|||
{ |
|||
{ 0, 1 }, |
|||
{ -1, 0 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <copyright file="ScharrProcessor.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>
|
|||
/// The Scharr operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators"/>
|
|||
/// </summary>
|
|||
public class ScharrProcessor : EdgeDetector2DFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => new float[,] |
|||
{ |
|||
{ -3, 0, 3 }, |
|||
{ -10, 0, 10 }, |
|||
{ -3, 0, 3 } |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => new float[,] |
|||
{ |
|||
{ 3, 10, 3 }, |
|||
{ 0, 0, 0 }, |
|||
{ -3, -10, -3 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// <copyright file="SobelProcessor.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>
|
|||
/// The Sobel operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>
|
|||
/// </summary>
|
|||
public class SobelProcessor : EdgeDetector2DFilter |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => new float[,] |
|||
{ |
|||
{ -1, 0, 1 }, |
|||
{ -2, 0, 2 }, |
|||
{ -1, 0, 1 } |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => new float[,] |
|||
{ |
|||
{ 1, 2, 1 }, |
|||
{ 0, 0, 0 }, |
|||
{ -1, -2, -1 } |
|||
}; |
|||
} |
|||
} |
|||
@ -1,140 +0,0 @@ |
|||
// <copyright file="GuassianBlurProcessor.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; |
|||
|
|||
/// <summary>
|
|||
/// Applies a Gaussian blur filter to the image.
|
|||
/// </summary>
|
|||
public class GuassianBlurProcessor : Convolution2PassFilter |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum size of the kernal in either direction.
|
|||
/// </summary>
|
|||
private readonly int kernelSize; |
|||
|
|||
/// <summary>
|
|||
/// The spread of the blur.
|
|||
/// </summary>
|
|||
private readonly float sigma; |
|||
|
|||
/// <summary>
|
|||
/// The vertical kernel
|
|||
/// </summary>
|
|||
private float[,] kernelY; |
|||
|
|||
/// <summary>
|
|||
/// The horizontal kernel
|
|||
/// </summary>
|
|||
private float[,] kernelX; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianBlurProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
|
|||
public GuassianBlurProcessor(float sigma = 3f) |
|||
{ |
|||
this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; |
|||
this.sigma = sigma; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianBlurProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="radius">
|
|||
/// The 'radius' value representing the size of the area to sample.
|
|||
/// </param>
|
|||
public GuassianBlurProcessor(int radius) |
|||
{ |
|||
this.kernelSize = (radius * 2) + 1; |
|||
this.sigma = radius; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianBlurProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sigma">
|
|||
/// The 'sigma' value representing the weight of the blur.
|
|||
/// </param>
|
|||
/// <param name="radius">
|
|||
/// The 'radius' value representing the size of the area to sample.
|
|||
/// This should be at least twice the sigma value.
|
|||
/// </param>
|
|||
public GuassianBlurProcessor(float sigma, int radius) |
|||
{ |
|||
this.kernelSize = (radius * 2) + 1; |
|||
this.sigma = sigma; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => this.kernelX; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => this.kernelY; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
if (this.kernelY == null) |
|||
{ |
|||
this.kernelY = this.CreateGaussianKernel(false); |
|||
} |
|||
|
|||
if (this.kernelX == null) |
|||
{ |
|||
this.kernelX = this.CreateGaussianKernel(true); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
|
|||
/// </summary>
|
|||
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
|
|||
/// <returns>The <see cref="T:float[,]"/></returns>
|
|||
private float[,] CreateGaussianKernel(bool horizontal) |
|||
{ |
|||
int size = this.kernelSize; |
|||
float weight = this.sigma; |
|||
float[,] kernel = horizontal ? new float[1, size] : new float[size, 1]; |
|||
float sum = 0.0f; |
|||
|
|||
float midpoint = (size - 1) / 2f; |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
float x = i - midpoint; |
|||
float gx = ImageMaths.Gaussian(x, weight); |
|||
sum += gx; |
|||
if (horizontal) |
|||
{ |
|||
kernel[0, i] = gx; |
|||
} |
|||
else |
|||
{ |
|||
kernel[i, 0] = gx; |
|||
} |
|||
} |
|||
|
|||
// Normalise kernel so that the sum of all weights equals 1
|
|||
if (horizontal) |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[0, i] = kernel[0, i] / sum; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[i, 0] = kernel[i, 0] / sum; |
|||
} |
|||
} |
|||
|
|||
return kernel; |
|||
} |
|||
} |
|||
} |
|||
@ -1,178 +0,0 @@ |
|||
// <copyright file="GuassianSharpenProcessor.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; |
|||
|
|||
/// <summary>
|
|||
/// Applies a Gaussian sharpening filter to the image.
|
|||
/// </summary>
|
|||
public class GuassianSharpenProcessor : Convolution2PassFilter |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum size of the kernal in either direction.
|
|||
/// </summary>
|
|||
private readonly int kernelSize; |
|||
|
|||
/// <summary>
|
|||
/// The spread of the blur.
|
|||
/// </summary>
|
|||
private readonly float sigma; |
|||
|
|||
/// <summary>
|
|||
/// The vertical kernel
|
|||
/// </summary>
|
|||
private float[,] kernelY; |
|||
|
|||
/// <summary>
|
|||
/// The horizontal kernel
|
|||
/// </summary>
|
|||
private float[,] kernelX; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianSharpenProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sigma">
|
|||
/// The 'sigma' value representing the weight of the sharpening.
|
|||
/// </param>
|
|||
public GuassianSharpenProcessor(float sigma = 3f) |
|||
{ |
|||
this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; |
|||
this.sigma = sigma; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianSharpenProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="radius">
|
|||
/// The 'radius' value representing the size of the area to sample.
|
|||
/// </param>
|
|||
public GuassianSharpenProcessor(int radius) |
|||
{ |
|||
this.kernelSize = (radius * 2) + 1; |
|||
this.sigma = radius; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GuassianSharpenProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sigma">
|
|||
/// The 'sigma' value representing the weight of the sharpen.
|
|||
/// </param>
|
|||
/// <param name="radius">
|
|||
/// The 'radius' value representing the size of the area to sample.
|
|||
/// This should be at least twice the sigma value.
|
|||
/// </param>
|
|||
public GuassianSharpenProcessor(float sigma, int radius) |
|||
{ |
|||
this.kernelSize = (radius * 2) + 1; |
|||
this.sigma = sigma; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelX => this.kernelX; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override float[,] KernelY => this.kernelY; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
if (this.kernelY == null) |
|||
{ |
|||
this.kernelY = this.CreateGaussianKernel(false); |
|||
} |
|||
|
|||
if (this.kernelX == null) |
|||
{ |
|||
this.kernelX = this.CreateGaussianKernel(true); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
|
|||
/// </summary>
|
|||
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
|
|||
/// <returns>The <see cref="T:float[,]"/></returns>
|
|||
private float[,] CreateGaussianKernel(bool horizontal) |
|||
{ |
|||
int size = this.kernelSize; |
|||
float weight = this.sigma; |
|||
float[,] kernel = horizontal ? new float[1, size] : new float[size, 1]; |
|||
float sum = 0; |
|||
|
|||
float midpoint = (size - 1) / 2f; |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
float x = i - midpoint; |
|||
float gx = ImageMaths.Gaussian(x, weight); |
|||
sum += gx; |
|||
if (horizontal) |
|||
{ |
|||
kernel[0, i] = gx; |
|||
} |
|||
else |
|||
{ |
|||
kernel[i, 0] = gx; |
|||
} |
|||
} |
|||
|
|||
// Invert the kernel for sharpening.
|
|||
int midpointRounded = (int)midpoint; |
|||
|
|||
if (horizontal) |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
if (i == midpointRounded) |
|||
{ |
|||
// Calculate central value
|
|||
kernel[0, i] = (2f * sum) - kernel[0, i]; |
|||
} |
|||
else |
|||
{ |
|||
// invert value
|
|||
kernel[0, i] = -kernel[0, i]; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
if (i == midpointRounded) |
|||
{ |
|||
// Calculate central value
|
|||
kernel[i, 0] = (2 * sum) - kernel[i, 0]; |
|||
} |
|||
else |
|||
{ |
|||
// invert value
|
|||
kernel[i, 0] = -kernel[i, 0]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Normalise kernel so that the sum of all weights equals 1
|
|||
if (horizontal) |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[0, i] = kernel[0, i] / sum; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[i, 0] = kernel[i, 0] / sum; |
|||
} |
|||
} |
|||
|
|||
return kernel; |
|||
} |
|||
} |
|||
} |
|||
@ -1,64 +0,0 @@ |
|||
// <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>
|
|||
public class GlowProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the glow color to apply.
|
|||
/// </summary>
|
|||
public Color Color { get; set; } = Color.White; |
|||
|
|||
/// <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 target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Color glowColor = this.Color; |
|||
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 (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
float distance = Vector2.Distance(centre, new Vector2(x, y)); |
|||
Color sourceColor = sourcePixels[x, y]; |
|||
targetPixels[x, y] = Color.Lerp(glowColor, sourceColor, .5f * (distance / maxDistance)); |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,48 +0,0 @@ |
|||
// <copyright file="InvertProcessor.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; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// An <see cref="IImageProcessor"/> to invert the colors of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
public class InvertProcessor : ImageProcessor |
|||
{ |
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Vector3 inverseVector = Vector3.One; |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
Color color = sourcePixels[x, y]; |
|||
Vector3 vector = inverseVector - color.ToVector3(); |
|||
targetPixels[x, y] = new Color(vector, color.A); |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,94 +0,0 @@ |
|||
// <copyright file="PixelateProcessor.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.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// An <see cref="IImageProcessor"/> to invert the colors of an <see cref="Image"/>.
|
|||
/// </summary>
|
|||
public class PixelateProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PixelateProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="size">The size of the pixels. Must be greater than 0.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <paramref name="size"/> is less than 0 or equal to 0.
|
|||
/// </exception>
|
|||
public PixelateProcessor(int size) |
|||
{ |
|||
Guard.MustBeGreaterThan(size, 0, nameof(size)); |
|||
this.Value = size; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or the pixel size.
|
|||
/// </summary>
|
|||
public int Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int sourceY = sourceRectangle.Y; |
|||
int sourceBottom = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
int size = this.Value; |
|||
int offset = this.Value / 2; |
|||
|
|||
// Get the range on the y-plane to choose from.
|
|||
IEnumerable<int> range = EnumerableExtensions.SteppedRange(startY, i => i < endY, size); |
|||
|
|||
using (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.ForEach( |
|||
range, |
|||
y => |
|||
{ |
|||
if (y >= sourceY && y < sourceBottom) |
|||
{ |
|||
for (int x = startX; x < endX; x += size) |
|||
{ |
|||
int offsetX = offset; |
|||
int offsetY = offset; |
|||
|
|||
// Make sure that the offset is within the boundary of the
|
|||
// image.
|
|||
while (y + offsetY >= sourceBottom) |
|||
{ |
|||
offsetY--; |
|||
} |
|||
|
|||
while (x + offsetX >= endX) |
|||
{ |
|||
offsetX--; |
|||
} |
|||
|
|||
// Get the pixel color in the centre of the soon to be pixelated area.
|
|||
// ReSharper disable AccessToDisposedClosure
|
|||
Color pixel = sourcePixels[x + offsetX, y + offsetY]; |
|||
|
|||
// For each pixel in the pixelate size, set it to the centre color.
|
|||
for (int l = y; l < y + size && l < sourceBottom; l++) |
|||
{ |
|||
for (int k = x; k < x + size && k < endX; k++) |
|||
{ |
|||
targetPixels[k, l] = pixel; |
|||
} |
|||
} |
|||
} |
|||
|
|||
this.OnRowProcessed(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,63 +0,0 @@ |
|||
// <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>
|
|||
public class VignetteProcessor : ImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the vignette color to apply.
|
|||
/// </summary>
|
|||
public Color Color { get; set; } = Color.Black; |
|||
|
|||
/// <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 target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
Color vignetteColor = this.Color; |
|||
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 (PixelAccessor sourcePixels = source.Lock()) |
|||
using (PixelAccessor targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
float distance = Vector2.Distance(centre, new Vector2(x, y)); |
|||
Color sourceColor = sourcePixels[x, y]; |
|||
targetPixels[x, y] = Color.Lerp(vignetteColor, sourceColor, 1 - .9f * distance / maxDistance); |
|||
} |
|||
this.OnRowProcessed(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,52 +0,0 @@ |
|||
// <copyright file="Saturation.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Alters the saturation component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="amount">The new saturation of the image. Must be between -100 and 100.</param>
|
|||
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
|
|||
/// <returns>The <see cref="Image"/>.</returns>
|
|||
public static Image Saturation(this Image source, int amount, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Saturation(source, amount, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Alters the saturation component of the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="amount">The new saturation of the image. Must be between -100 and 100.</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"/>.</returns>
|
|||
public static Image Saturation(this Image source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
SaturationProcessor processor = new SaturationProcessor(amount); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <copyright file="Sepia.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"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies sepia toning to the image.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Sepia(this Image source, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
return Sepia(source, source.Bounds, progressHandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies sepia toning to the image.
|
|||
/// </summary>
|
|||
/// <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"/>.</returns>
|
|||
public static Image Sepia(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null) |
|||
{ |
|||
SepiaProcessor processor = new SepiaProcessor(); |
|||
processor.OnProgress += progressHandler; |
|||
|
|||
try |
|||
{ |
|||
return source.Process(rectangle, processor); |
|||
} |
|||
finally |
|||
{ |
|||
processor.OnProgress -= progressHandler; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
// <copyright file="BmpBitsPerPixel.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerates the available bits per pixel for bitmap.
|
|||
/// </summary>
|
|||
public enum BmpBitsPerPixel |
|||
{ |
|||
/// <summary>
|
|||
/// 24 bits per pixel. Each pixel consists of 3 bytes.
|
|||
/// </summary>
|
|||
Pixel24 = 3, |
|||
|
|||
/// <summary>
|
|||
/// 32 bits per pixel. Each pixel consists of 4 bytes.
|
|||
/// </summary>
|
|||
Pixel32 = 4, |
|||
} |
|||
} |
|||
@ -1,63 +0,0 @@ |
|||
// <copyright file="BmpCompression.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Defines how the compression type of the image data
|
|||
/// in the bitmap file.
|
|||
/// </summary>
|
|||
internal enum BmpCompression |
|||
{ |
|||
/// <summary>
|
|||
/// Each image row has a multiple of four elements. If the
|
|||
/// row has less elements, zeros will be added at the right side.
|
|||
/// The format depends on the number of bits, stored in the info header.
|
|||
/// If the number of bits are one, four or eight each pixel data is
|
|||
/// a index to the palette. If the number of bits are sixteen,
|
|||
/// twenty-four or thirty-two each pixel contains a color.
|
|||
/// </summary>
|
|||
RGB = 0, |
|||
|
|||
/// <summary>
|
|||
/// Two bytes are one data record. If the first byte is not zero, the
|
|||
/// next two half bytes will be repeated as much as the value of the first byte.
|
|||
/// If the first byte is zero, the record has different meanings, depending
|
|||
/// on the second byte. If the second byte is zero, it is the end of the row,
|
|||
/// if it is one, it is the end of the image.
|
|||
/// Not supported at the moment.
|
|||
/// </summary>
|
|||
RLE8 = 1, |
|||
|
|||
/// <summary>
|
|||
/// Two bytes are one data record. If the first byte is not zero, the
|
|||
/// next byte will be repeated as much as the value of the first byte.
|
|||
/// If the first byte is zero, the record has different meanings, depending
|
|||
/// on the second byte. If the second byte is zero, it is the end of the row,
|
|||
/// if it is one, it is the end of the image.
|
|||
/// Not supported at the moment.
|
|||
/// </summary>
|
|||
RLE4 = 2, |
|||
|
|||
/// <summary>
|
|||
/// Each image row has a multiple of four elements. If the
|
|||
/// row has less elements, zeros will be added at the right side.
|
|||
/// Not supported at the moment.
|
|||
/// </summary>
|
|||
BitFields = 3, |
|||
|
|||
/// <summary>
|
|||
/// The bitmap contains a JPG image.
|
|||
/// Not supported at the moment.
|
|||
/// </summary>
|
|||
JPEG = 4, |
|||
|
|||
/// <summary>
|
|||
/// The bitmap contains a PNG image.
|
|||
/// Not supported at the moment.
|
|||
/// </summary>
|
|||
PNG = 5 |
|||
} |
|||
} |
|||
@ -1,82 +0,0 @@ |
|||
// <copyright file="BmpDecoder.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
/// <summary>
|
|||
/// Image decoder for generating an image out of a Windows bitmap stream.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Does not support the following formats at the moment:
|
|||
/// <list type="bullet">
|
|||
/// <item>JPG</item>
|
|||
/// <item>PNG</item>
|
|||
/// <item>RLE4</item>
|
|||
/// <item>RLE8</item>
|
|||
/// <item>BitFields</item>
|
|||
/// </list>
|
|||
/// Formats will be supported in a later releases. We advise always
|
|||
/// to use only 24 Bit Windows bitmaps.
|
|||
/// </remarks>
|
|||
public class BmpDecoder : IImageDecoder |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the size of the header for this image type.
|
|||
/// </summary>
|
|||
/// <value>The size of the header.</value>
|
|||
public int HeaderSize => 2; |
|||
|
|||
/// <summary>
|
|||
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
|
|||
/// file header.
|
|||
/// </summary>
|
|||
/// <param name="extension">The <see cref="string"/> containing the file extension.</param>
|
|||
/// <returns>
|
|||
/// True if the decoder supports the file extension; otherwise, false.
|
|||
/// </returns>
|
|||
public bool IsSupportedFileExtension(string extension) |
|||
{ |
|||
Guard.NotNullOrEmpty(extension, "extension"); |
|||
|
|||
extension = extension.StartsWith(".") ? extension.Substring(1) : extension; |
|||
|
|||
return extension.Equals("BMP", StringComparison.OrdinalIgnoreCase) |
|||
|| extension.Equals("DIP", StringComparison.OrdinalIgnoreCase); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
|
|||
/// file header.
|
|||
/// </summary>
|
|||
/// <param name="header">The <see cref="T:byte[]"/> containing the file header.</param>
|
|||
/// <returns>
|
|||
/// True if the decoder supports the file header; otherwise, false.
|
|||
/// </returns>
|
|||
public bool IsSupportedFileFormat(byte[] header) |
|||
{ |
|||
bool isBmp = false; |
|||
if (header.Length >= 2) |
|||
{ |
|||
isBmp = header[0] == 0x42 && // B
|
|||
header[1] == 0x4D; // M
|
|||
} |
|||
|
|||
return isBmp; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decodes the image from the specified stream to the <see cref="ImageBase"/>.
|
|||
/// </summary>
|
|||
/// <param name="image">The <see cref="ImageBase"/> to decode to.</param>
|
|||
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
|
|||
public void Decode(Image image, Stream stream) |
|||
{ |
|||
new BmpDecoderCore().Decode(image, stream); |
|||
} |
|||
} |
|||
} |
|||
@ -1,445 +0,0 @@ |
|||
// <copyright file="BmpDecoderCore.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Performs the bmp decoding operation.
|
|||
/// </summary>
|
|||
internal sealed class BmpDecoderCore |
|||
{ |
|||
/// <summary>
|
|||
/// The mask for the red part of the color for 16 bit rgb bitmaps.
|
|||
/// </summary>
|
|||
private const int Rgb16RMask = 0x00007C00; |
|||
|
|||
/// <summary>
|
|||
/// The mask for the green part of the color for 16 bit rgb bitmaps.
|
|||
/// </summary>
|
|||
private const int Rgb16GMask = 0x000003E0; |
|||
|
|||
/// <summary>
|
|||
/// The mask for the blue part of the color for 16 bit rgb bitmaps.
|
|||
/// </summary>
|
|||
private const int Rgb16BMask = 0x0000001F; |
|||
|
|||
/// <summary>
|
|||
/// The stream to decode from.
|
|||
/// </summary>
|
|||
private Stream currentStream; |
|||
|
|||
/// <summary>
|
|||
/// The file header containing general information.
|
|||
/// TODO: Why is this not used? We advance the stream but do not use the values parsed.
|
|||
/// </summary>
|
|||
private BmpFileHeader fileHeader; |
|||
|
|||
/// <summary>
|
|||
/// The info header containing detailed information about the bitmap.
|
|||
/// </summary>
|
|||
private BmpInfoHeader infoHeader; |
|||
|
|||
/// <summary>
|
|||
/// Decodes the image from the specified this._stream and sets
|
|||
/// the data to image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
|
|||
/// <param name="image">The image, where the data should be set to.
|
|||
/// Cannot be null (Nothing in Visual Basic).</param>
|
|||
/// <param name="stream">The this._stream, where the image should be
|
|||
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
|
|||
/// <exception cref="ArgumentNullException">
|
|||
/// <para><paramref name="image"/> is null.</para>
|
|||
/// <para>- or -</para>
|
|||
/// <para><paramref name="stream"/> is null.</para>
|
|||
/// </exception>
|
|||
public void Decode<TPackedVector>(Image<TPackedVector> image, Stream stream) |
|||
where TPackedVector : IPackedVector, new() |
|||
{ |
|||
this.currentStream = stream; |
|||
|
|||
try |
|||
{ |
|||
this.ReadFileHeader(); |
|||
this.ReadInfoHeader(); |
|||
|
|||
// see http://www.drdobbs.com/architecture-and-design/the-bmp-file-format-part-1/184409517
|
|||
// If the height is negative, then this is a Windows bitmap whose origin
|
|||
// is the upper-left corner and not the lower-left.The inverted flag
|
|||
// indicates a lower-left origin.Our code will be outputting an
|
|||
// upper-left origin pixel array.
|
|||
bool inverted = false; |
|||
if (this.infoHeader.Height < 0) |
|||
{ |
|||
inverted = true; |
|||
this.infoHeader.Height = -this.infoHeader.Height; |
|||
} |
|||
|
|||
int colorMapSize = -1; |
|||
|
|||
if (this.infoHeader.ClrUsed == 0) |
|||
{ |
|||
if (this.infoHeader.BitsPerPixel == 1 || |
|||
this.infoHeader.BitsPerPixel == 4 || |
|||
this.infoHeader.BitsPerPixel == 8) |
|||
{ |
|||
colorMapSize = (int)Math.Pow(2, this.infoHeader.BitsPerPixel) * 4; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
colorMapSize = this.infoHeader.ClrUsed * 4; |
|||
} |
|||
|
|||
byte[] palette = null; |
|||
|
|||
if (colorMapSize > 0) |
|||
{ |
|||
// 255 * 4
|
|||
if (colorMapSize > 1020) |
|||
{ |
|||
throw new ImageFormatException($"Invalid bmp colormap size '{colorMapSize}'"); |
|||
} |
|||
|
|||
palette = new byte[colorMapSize]; |
|||
|
|||
this.currentStream.Read(palette, 0, colorMapSize); |
|||
} |
|||
|
|||
if (this.infoHeader.Width > image.MaxWidth || this.infoHeader.Height > image.MaxHeight) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
$"The input bitmap '{this.infoHeader.Width}x{this.infoHeader.Height}' is " |
|||
+ $"bigger then the max allowed size '{image.MaxWidth}x{image.MaxHeight}'"); |
|||
} |
|||
|
|||
TPackedVector[] imageData = new TPackedVector[this.infoHeader.Width * this.infoHeader.Height]; |
|||
|
|||
switch (this.infoHeader.Compression) |
|||
{ |
|||
case BmpCompression.RGB: |
|||
if (this.infoHeader.HeaderSize != 40) |
|||
{ |
|||
throw new ImageFormatException( |
|||
$"Header Size value '{this.infoHeader.HeaderSize}' is not valid."); |
|||
} |
|||
|
|||
if (this.infoHeader.BitsPerPixel == 32) |
|||
{ |
|||
this.ReadRgb32(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted); |
|||
} |
|||
else if (this.infoHeader.BitsPerPixel == 24) |
|||
{ |
|||
this.ReadRgb24(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted); |
|||
} |
|||
else if (this.infoHeader.BitsPerPixel == 16) |
|||
{ |
|||
this.ReadRgb16(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted); |
|||
} |
|||
else if (this.infoHeader.BitsPerPixel <= 8) |
|||
{ |
|||
this.ReadRgbPalette( |
|||
imageData, |
|||
palette, |
|||
this.infoHeader.Width, |
|||
this.infoHeader.Height, |
|||
this.infoHeader.BitsPerPixel, |
|||
inverted); |
|||
} |
|||
|
|||
break; |
|||
default: |
|||
throw new NotSupportedException("Does not support this kind of bitmap files."); |
|||
} |
|||
|
|||
image.SetPixels(this.infoHeader.Width, this.infoHeader.Height, imageData); |
|||
} |
|||
catch (IndexOutOfRangeException e) |
|||
{ |
|||
throw new ImageFormatException("Bitmap does not have a valid format.", e); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the y- value based on the given height.
|
|||
/// </summary>
|
|||
/// <param name="y">The y- value representing the current row.</param>
|
|||
/// <param name="height">The height of the bitmap.</param>
|
|||
/// <returns>The <see cref="int"/> representing the inverted value.</returns>
|
|||
private static int Invert(int y, int height, bool inverted) |
|||
{ |
|||
int row; |
|||
|
|||
if (!inverted) |
|||
{ |
|||
row = height - y - 1; |
|||
} |
|||
else |
|||
{ |
|||
row = y; |
|||
} |
|||
|
|||
return row; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reads the color palette from the stream.
|
|||
/// </summary>
|
|||
/// <param name="imageData">The <see cref="T:float[]"/> image data to assign the palette to.</param>
|
|||
/// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
|
|||
/// <param name="width">The width of the bitmap.</param>
|
|||
/// <param name="height">The height of the bitmap.</param>
|
|||
/// <param name="bits">The number of bits per pixel.</param>
|
|||
private void ReadRgbPalette(float[] imageData, byte[] colors, int width, int height, int bits, bool inverted) |
|||
{ |
|||
// Pixels per byte (bits per pixel)
|
|||
int ppb = 8 / bits; |
|||
|
|||
int arrayWidth = (width + ppb - 1) / ppb; |
|||
|
|||
// Bit mask
|
|||
int mask = 0xFF >> (8 - bits); |
|||
|
|||
byte[] data = new byte[arrayWidth * height]; |
|||
|
|||
this.currentStream.Read(data, 0, data.Length); |
|||
|
|||
// Rows are aligned on 4 byte boundaries
|
|||
int alignment = arrayWidth % 4; |
|||
if (alignment != 0) |
|||
{ |
|||
alignment = 4 - alignment; |
|||
} |
|||
|
|||
Parallel.For( |
|||
0, |
|||
height, |
|||
y => |
|||
{ |
|||
int rowOffset = y * (arrayWidth + alignment); |
|||
|
|||
for (int x = 0; x < arrayWidth; x++) |
|||
{ |
|||
int offset = rowOffset + x; |
|||
|
|||
// Revert the y value, because bitmaps are saved from down to top
|
|||
int row = Invert(y, height, inverted); |
|||
|
|||
int colOffset = x * ppb; |
|||
|
|||
for (int shift = 0; shift < ppb && (colOffset + shift) < width; shift++) |
|||
{ |
|||
int colorIndex = ((data[offset] >> (8 - bits - (shift * bits))) & mask) * 4; |
|||
int arrayOffset = ((row * width) + (colOffset + shift)) * 4; |
|||
|
|||
// We divide by 255 as we will store the colors in our floating point format.
|
|||
// Stored in r-> g-> b-> a order.
|
|||
imageData[arrayOffset] = colors[colorIndex + 2] / 255f; // r
|
|||
imageData[arrayOffset + 1] = colors[colorIndex + 1] / 255f; // g
|
|||
imageData[arrayOffset + 2] = colors[colorIndex] / 255f; // b
|
|||
imageData[arrayOffset + 3] = 1; // a
|
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reads the 16 bit color palette from the stream
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
|
|||
/// <param name="imageData">The <see cref="TPackedVector[]"/> image data to assign the palette to.</param>
|
|||
/// <param name="width">The width of the bitmap.</param>
|
|||
/// <param name="height">The height of the bitmap.</param>
|
|||
private void ReadRgb16<TPackedVector>(TPackedVector[] imageData, int width, int height, bool inverted) |
|||
where TPackedVector : IPackedVector, new() |
|||
{ |
|||
// We divide here as we will store the colors in our floating point format.
|
|||
const int ScaleR = 8; // 256/32
|
|||
const int ScaleG = 4; // 256/64
|
|||
|
|||
int alignment; |
|||
byte[] data = this.GetImageArray(width, height, 2, out alignment); |
|||
|
|||
Parallel.For( |
|||
0, |
|||
height, |
|||
y => |
|||
{ |
|||
int rowOffset = y * ((width * 2) + alignment); |
|||
|
|||
// Revert the y value, because bitmaps are saved from down to top
|
|||
int row = Invert(y, height, inverted); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
int offset = rowOffset + (x * 2); |
|||
|
|||
short temp = BitConverter.ToInt16(data, offset); |
|||
|
|||
byte r = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR); |
|||
byte g = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG); |
|||
byte b = (byte)((temp & Rgb16BMask) * ScaleR); |
|||
|
|||
int arrayOffset = ((row * width) + x); |
|||
|
|||
// Stored in b-> g-> r-> a order.
|
|||
TPackedVector packed = new TPackedVector(); |
|||
packed.PackBytes(b, g, r, 255); |
|||
imageData[arrayOffset] = packed; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reads the 24 bit color palette from the stream
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
|
|||
/// <param name="imageData">The <see cref="TPackedVector[]"/> image data to assign the palette to.</param>
|
|||
/// <param name="width">The width of the bitmap.</param>
|
|||
/// <param name="height">The height of the bitmap.</param>
|
|||
private void ReadRgb24<TPackedVector>(TPackedVector[] imageData, int width, int height, bool inverted) |
|||
where TPackedVector : IPackedVector, new() |
|||
{ |
|||
int alignment; |
|||
byte[] data = this.GetImageArray(width, height, 3, out alignment); |
|||
|
|||
Parallel.For( |
|||
0, |
|||
height, |
|||
y => |
|||
{ |
|||
int rowOffset = y * ((width * 3) + alignment); |
|||
|
|||
// Revert the y value, because bitmaps are saved from down to top
|
|||
int row = Invert(y, height, inverted); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
int offset = rowOffset + (x * 3); |
|||
int arrayOffset = ((row * width) + x); |
|||
|
|||
// We divide by 255 as we will store the colors in our floating point format.
|
|||
// Stored in b-> g-> r-> a order.
|
|||
TPackedVector packed = new TPackedVector(); |
|||
packed.PackBytes(data[offset], data[offset + 1], data[offset + 2], 255); |
|||
imageData[arrayOffset] = packed; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reads the 32 bit color palette from the stream
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
|
|||
/// <param name="imageData">The <see cref="TPackedVector[]"/> image data to assign the palette to.</param>
|
|||
/// <param name="width">The width of the bitmap.</param>
|
|||
/// <param name="height">The height of the bitmap.</param>
|
|||
private void ReadRgb32<TPackedVector>(TPackedVector[] imageData, int width, int height, bool inverted) |
|||
where TPackedVector : IPackedVector, new() |
|||
{ |
|||
int alignment; |
|||
byte[] data = this.GetImageArray(width, height, 4, out alignment); |
|||
|
|||
Parallel.For( |
|||
0, |
|||
height, |
|||
y => |
|||
{ |
|||
int rowOffset = y * ((width * 4) + alignment); |
|||
|
|||
// Revert the y value, because bitmaps are saved from down to top
|
|||
int row = Invert(y, height, inverted); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
int offset = rowOffset + (x * 4); |
|||
int arrayOffset = ((row * width) + x); |
|||
|
|||
// Stored in b-> g-> r-> a order.
|
|||
TPackedVector packed = new TPackedVector(); |
|||
packed.PackBytes(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); |
|||
imageData[arrayOffset] = packed; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a <see cref="T:byte[]"/> containing the pixels for the current bitmap.
|
|||
/// </summary>
|
|||
/// <param name="width">The width of the bitmap.</param>
|
|||
/// <param name="height">The height.</param>
|
|||
/// <param name="bytes">The number of bytes per pixel.</param>
|
|||
/// <param name="alignment">The alignment of the pixels.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/> containing the pixels.
|
|||
/// </returns>
|
|||
private byte[] GetImageArray(int width, int height, int bytes, out int alignment) |
|||
{ |
|||
int dataWidth = width; |
|||
|
|||
alignment = (width * bytes) % 4; |
|||
|
|||
if (alignment != 0) |
|||
{ |
|||
alignment = 4 - alignment; |
|||
} |
|||
|
|||
int size = ((dataWidth * bytes) + alignment) * height; |
|||
|
|||
byte[] data = new byte[size]; |
|||
|
|||
this.currentStream.Read(data, 0, size); |
|||
|
|||
return data; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reads the <see cref="BmpInfoHeader"/> from the stream.
|
|||
/// </summary>
|
|||
private void ReadInfoHeader() |
|||
{ |
|||
byte[] data = new byte[BmpInfoHeader.Size]; |
|||
|
|||
this.currentStream.Read(data, 0, BmpInfoHeader.Size); |
|||
|
|||
this.infoHeader = new BmpInfoHeader |
|||
{ |
|||
HeaderSize = BitConverter.ToInt32(data, 0), |
|||
Width = BitConverter.ToInt32(data, 4), |
|||
Height = BitConverter.ToInt32(data, 8), |
|||
Planes = BitConverter.ToInt16(data, 12), |
|||
BitsPerPixel = BitConverter.ToInt16(data, 14), |
|||
ImageSize = BitConverter.ToInt32(data, 20), |
|||
XPelsPerMeter = BitConverter.ToInt32(data, 24), |
|||
YPelsPerMeter = BitConverter.ToInt32(data, 28), |
|||
ClrUsed = BitConverter.ToInt32(data, 32), |
|||
ClrImportant = BitConverter.ToInt32(data, 36), |
|||
Compression = (BmpCompression)BitConverter.ToInt32(data, 16) |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reads the <see cref="BmpFileHeader"/> from the stream.
|
|||
/// </summary>
|
|||
private void ReadFileHeader() |
|||
{ |
|||
byte[] data = new byte[BmpFileHeader.Size]; |
|||
|
|||
this.currentStream.Read(data, 0, BmpFileHeader.Size); |
|||
|
|||
this.fileHeader = new BmpFileHeader |
|||
{ |
|||
Type = BitConverter.ToInt16(data, 0), |
|||
FileSize = BitConverter.ToInt32(data, 2), |
|||
Reserved = BitConverter.ToInt32(data, 6), |
|||
Offset = BitConverter.ToInt32(data, 10) |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -1,53 +0,0 @@ |
|||
// <copyright file="BmpEncoder.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream as a Windows bitmap.
|
|||
/// </summary>
|
|||
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
|
|||
public class BmpEncoder : IImageEncoder |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the quality of output for images.
|
|||
/// </summary>
|
|||
/// <remarks>Bitmap is a lossless format so this is not used in this encoder.</remarks>
|
|||
public int Quality { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public string MimeType => "image/bmp"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public string Extension => "bmp"; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the number of bits per pixel.
|
|||
/// </summary>
|
|||
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool IsSupportedFileExtension(string extension) |
|||
{ |
|||
Guard.NotNullOrEmpty(extension, nameof(extension)); |
|||
|
|||
extension = extension.StartsWith(".") ? extension.Substring(1) : extension; |
|||
|
|||
return extension.Equals(this.Extension, StringComparison.OrdinalIgnoreCase) |
|||
|| extension.Equals("dip", StringComparison.OrdinalIgnoreCase); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Encode<TPackedVector>(ImageBase<TPackedVector> image, Stream stream) |
|||
where TPackedVector: IPackedVector |
|||
{ |
|||
BmpEncoderCore encoder = new BmpEncoderCore(); |
|||
encoder.Encode(image, stream, this.BitsPerPixel); |
|||
} |
|||
} |
|||
} |
|||
@ -1,205 +0,0 @@ |
|||
// <copyright file="BmpEncoderCore.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
using IO; |
|||
|
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream as a Windows bitmap.
|
|||
/// </summary>
|
|||
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
|
|||
internal sealed class BmpEncoderCore |
|||
{ |
|||
/// <summary>
|
|||
/// The number of bits per pixel.
|
|||
/// </summary>
|
|||
private BmpBitsPerPixel bmpBitsPerPixel; |
|||
|
|||
/// <summary>
|
|||
/// Encodes the image to the specified stream from the <see cref="ImageBase{TPackedVector}"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
|
|||
/// <param name="image">The <see cref="ImageBase{TPackedVector}"/> to encode from.</param>
|
|||
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
|
|||
/// <param name="bitsPerPixel">The <see cref="BmpBitsPerPixel"/></param>
|
|||
public void Encode<TPackedVector>(ImageBase<TPackedVector> image, Stream stream, BmpBitsPerPixel bitsPerPixel) |
|||
where TPackedVector : IPackedVector |
|||
{ |
|||
Guard.NotNull(image, nameof(image)); |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
this.bmpBitsPerPixel = bitsPerPixel; |
|||
|
|||
int rowWidth = image.Width; |
|||
|
|||
// TODO: Check this for varying file formats.
|
|||
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4; |
|||
if (amount != 0) |
|||
{ |
|||
rowWidth += 4 - amount; |
|||
} |
|||
|
|||
// Do not use IDisposable pattern here as we want to preserve the stream.
|
|||
EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream); |
|||
|
|||
int bpp = (int)this.bmpBitsPerPixel; |
|||
|
|||
BmpFileHeader fileHeader = new BmpFileHeader |
|||
{ |
|||
Type = 19778, // BM
|
|||
Offset = 54, |
|||
FileSize = 54 + (image.Height * rowWidth * bpp) |
|||
}; |
|||
|
|||
BmpInfoHeader infoHeader = new BmpInfoHeader |
|||
{ |
|||
HeaderSize = 40, |
|||
Height = image.Height, |
|||
Width = image.Width, |
|||
BitsPerPixel = (short)(8 * bpp), |
|||
Planes = 1, |
|||
ImageSize = image.Height * rowWidth * bpp, |
|||
ClrUsed = 0, |
|||
ClrImportant = 0 |
|||
}; |
|||
|
|||
WriteHeader(writer, fileHeader); |
|||
this.WriteInfo(writer, infoHeader); |
|||
this.WriteImage(writer, image); |
|||
|
|||
writer.Flush(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the bitmap header data to the binary stream.
|
|||
/// </summary>
|
|||
/// <param name="writer">
|
|||
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
|
|||
/// </param>
|
|||
/// <param name="fileHeader">
|
|||
/// The <see cref="BmpFileHeader"/> containing the header data.
|
|||
/// </param>
|
|||
private static void WriteHeader(EndianBinaryWriter writer, BmpFileHeader fileHeader) |
|||
{ |
|||
writer.Write(fileHeader.Type); |
|||
writer.Write(fileHeader.FileSize); |
|||
writer.Write(fileHeader.Reserved); |
|||
writer.Write(fileHeader.Offset); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the bitmap information to the binary stream.
|
|||
/// </summary>
|
|||
/// <param name="writer">
|
|||
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
|
|||
/// </param>
|
|||
/// <param name="infoHeader">
|
|||
/// The <see cref="BmpFileHeader"/> containing the detailed information about the image.
|
|||
/// </param>
|
|||
private void WriteInfo(EndianBinaryWriter writer, BmpInfoHeader infoHeader) |
|||
{ |
|||
writer.Write(infoHeader.HeaderSize); |
|||
writer.Write(infoHeader.Width); |
|||
writer.Write(infoHeader.Height); |
|||
writer.Write(infoHeader.Planes); |
|||
writer.Write(infoHeader.BitsPerPixel); |
|||
writer.Write((int)infoHeader.Compression); |
|||
writer.Write(infoHeader.ImageSize); |
|||
writer.Write(infoHeader.XPelsPerMeter); |
|||
writer.Write(infoHeader.YPelsPerMeter); |
|||
writer.Write(infoHeader.ClrUsed); |
|||
writer.Write(infoHeader.ClrImportant); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the pixel data to the binary stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
|
|||
/// <param name="writer">
|
|||
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
|
|||
/// </param>
|
|||
/// <param name="image">
|
|||
/// The <see cref="ImageBase{TPackedVector}"/> containing pixel data.
|
|||
/// </param>
|
|||
private void WriteImage<TPackedVector>(EndianBinaryWriter writer, ImageBase<TPackedVector> image) |
|||
where TPackedVector : IPackedVector |
|||
{ |
|||
// TODO: Add more compression formats.
|
|||
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4; |
|||
if (amount != 0) |
|||
{ |
|||
amount = 4 - amount; |
|||
} |
|||
|
|||
using (IPixelAccessor pixels = image.Lock()) |
|||
{ |
|||
switch (this.bmpBitsPerPixel) |
|||
{ |
|||
case BmpBitsPerPixel.Pixel32: |
|||
this.Write32bit(writer, pixels, amount); |
|||
break; |
|||
|
|||
case BmpBitsPerPixel.Pixel24: |
|||
this.Write24bit(writer, pixels, amount); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the 32bit color palette to the stream.
|
|||
/// </summary>
|
|||
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|||
/// <param name="pixels">The <see cref="IPixelAccessor"/> containing pixel data.</param>
|
|||
/// <param name="amount">The amount to pad each row by.</param>
|
|||
private void Write32bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount) |
|||
{ |
|||
for (int y = pixels.Height - 1; y >= 0; y--) |
|||
{ |
|||
for (int x = 0; x < pixels.Width; x++) |
|||
{ |
|||
// Convert back to b-> g-> r-> a order.
|
|||
byte[] bytes = pixels[x, y].ToBytes(); |
|||
writer.Write(bytes); |
|||
} |
|||
|
|||
// Pad
|
|||
for (int i = 0; i < amount; i++) |
|||
{ |
|||
writer.Write((byte)0); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the 24bit color palette to the stream.
|
|||
/// </summary>
|
|||
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|||
/// <param name="pixels">The <see cref="IPixelAccessor"/> containing pixel data.</param>
|
|||
/// <param name="amount">The amount to pad each row by.</param>
|
|||
private void Write24bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount) |
|||
{ |
|||
for (int y = pixels.Height - 1; y >= 0; y--) |
|||
{ |
|||
for (int x = 0; x < pixels.Width; x++) |
|||
{ |
|||
// Convert back to b-> g-> r-> a order.
|
|||
byte[] bytes = pixels[x, y].ToBytes(); |
|||
writer.Write(new[] { bytes[0], bytes[1], bytes[2] }); |
|||
} |
|||
|
|||
// Pad
|
|||
for (int i = 0; i < amount; i++) |
|||
{ |
|||
writer.Write((byte)0); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,49 +0,0 @@ |
|||
// <copyright file="BmpFileHeader.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Stores general information about the Bitmap file.
|
|||
/// <see href="https://en.wikipedia.org/wiki/BMP_file_format" />
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The first two bytes of the Bitmap file format
|
|||
/// (thus the Bitmap header) are stored in big-endian order.
|
|||
/// All of the other integer values are stored in little-endian format
|
|||
/// (i.e. least-significant byte first).
|
|||
/// </remarks>
|
|||
internal class BmpFileHeader |
|||
{ |
|||
/// <summary>
|
|||
/// Defines of the data structure in the bitmap file.
|
|||
/// </summary>
|
|||
public const int Size = 14; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the Bitmap identifier.
|
|||
/// The field used to identify the bitmap file: 0x42 0x4D
|
|||
/// (Hex code points for B and M)
|
|||
/// </summary>
|
|||
public short Type { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the size of the bitmap file in bytes.
|
|||
/// </summary>
|
|||
public int FileSize { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets any reserved data; actual value depends on the application
|
|||
/// that creates the image.
|
|||
/// </summary>
|
|||
public int Reserved { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the offset, i.e. starting address, of the byte where
|
|||
/// the bitmap data can be found.
|
|||
/// </summary>
|
|||
public int Offset { get; set; } |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// <copyright file="BmpFormat.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Encapsulates the means to encode and decode bitmap images.
|
|||
/// </summary>
|
|||
public class BmpFormat : IImageFormat |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public IImageDecoder Decoder => new BmpDecoder(); |
|||
|
|||
/// <inheritdoc/>
|
|||
public IImageEncoder Encoder => new BmpEncoder(); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue