1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-13 01:58:30 +00:00

Moved comparison, blending and conversion from color to a behavior-class to make it exchangeable

This commit is contained in:
Darth Affe 2019-02-25 21:25:09 +01:00
parent fa396127ea
commit 5d374db9ef
4 changed files with 113 additions and 42 deletions

View File

@ -0,0 +1,80 @@
namespace RGB.NET.Core
{
public class DefaultColorBehavior : IColorBehavior
{
#region Properties & Fields
private static DefaultColorBehavior _instance = new DefaultColorBehavior();
/// <summary>
/// Gets the singleton instance of <see cref="DefaultColorBehavior"/>.
/// </summary>
public static DefaultColorBehavior Instance { get; } = _instance;
#endregion
#region Constructors
private DefaultColorBehavior()
{ }
#endregion
#region Methods
/// <summary>
/// Converts the individual byte values of this <see cref="Color"/> to a human-readable string.
/// </summary>
/// <returns>A string that contains the individual byte values of this <see cref="Color"/>. For example "[A: 255, R: 255, G: 0, B: 0]".</returns>
public virtual string ToString(Color color) => $"[A: {color.GetA()}, R: {color.GetR()}, G: {color.GetG()}, B: {color.GetB()}]";
/// <summary>
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
/// </summary>
/// <param name="obj">The object to test.</param>
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
public virtual bool Equals(Color color, object obj)
{
if (!(obj is Color)) return false;
(double a, double r, double g, double b) = ((Color)obj).GetRGB();
return color.A.EqualsInTolerance(a) && color.R.EqualsInTolerance(r) && color.G.EqualsInTolerance(g) && color.B.EqualsInTolerance(b);
}
/// <summary>
/// Returns a hash code for this <see cref="Color" />.
/// </summary>
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
public virtual int GetHashCode(Color color)
{
unchecked
{
int hashCode = color.A.GetHashCode();
hashCode = (hashCode * 397) ^ color.R.GetHashCode();
hashCode = (hashCode * 397) ^ color.G.GetHashCode();
hashCode = (hashCode * 397) ^ color.B.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Blends a <see cref="Color"/> over this color.
/// </summary>
/// <param name="color">The <see cref="Color"/> to blend.</param>
public virtual Color Blend(Color baseColor, Color blendColor)
{
if (blendColor.A.EqualsInTolerance(0)) return baseColor;
if (blendColor.A.EqualsInTolerance(1))
return blendColor;
double resultA = (1.0 - ((1.0 - blendColor.A) * (1.0 - baseColor.A)));
double resultR = (((blendColor.R * blendColor.A) / resultA) + ((baseColor.R * baseColor.A * (1.0 - blendColor.A)) / resultA));
double resultG = (((blendColor.G * blendColor.A) / resultA) + ((baseColor.G * baseColor.A * (1.0 - blendColor.A)) / resultA));
double resultB = (((blendColor.B * blendColor.A) / resultA) + ((baseColor.B * baseColor.A * (1.0 - blendColor.A)) / resultA));
return new Color(resultA, resultR, resultG, resultB);
}
#endregion
}
}

View File

@ -0,0 +1,13 @@
namespace RGB.NET.Core
{
public interface IColorBehavior
{
string ToString(Color color);
bool Equals(Color color, object obj);
int GetHashCode(Color color);
Color Blend(Color baseColor, Color blendColor);
}
}

View File

@ -25,6 +25,16 @@ namespace RGB.NET.Core
#region Properties & Fields #region Properties & Fields
private static IColorBehavior _behavior = DefaultColorBehavior.Instance;
/// <summary>
/// Gets or sets the <see cref="IColorBehavior"/> used to perform operations on colors.
/// </summary>
public static IColorBehavior Behavior
{
get => _behavior;
set => _behavior = value ?? DefaultColorBehavior.Instance;
}
/// <summary> /// <summary>
/// Gets the alpha component value of this <see cref="Color"/> as percentage in the range [0..1]. /// Gets the alpha component value of this <see cref="Color"/> as percentage in the range [0..1].
/// </summary> /// </summary>
@ -179,62 +189,29 @@ namespace RGB.NET.Core
#region Methods #region Methods
/// <summary> /// <summary>
/// Converts the individual byte values of this <see cref="Color"/> to a human-readable string. /// Gets a human-readable string, as defined by the current <see cref="Behavior"/>.
/// </summary> /// </summary>
/// <returns>A string that contains the individual byte values of this <see cref="Color"/>. For example "[A: 255, R: 255, G: 0, B: 0]".</returns> /// <returns>A string that contains the individual byte values of this <see cref="Color"/>. Default format: "[A: 255, R: 255, G: 0, B: 0]".</returns>
public override string ToString() => $"[A: {this.GetA()}, R: {this.GetR()}, G: {this.GetG()}, B: {this.GetB()}]"; public override string ToString() => Behavior.ToString(this);
/// <summary> /// <summary>
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />. /// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
/// </summary> /// </summary>
/// <param name="obj">The object to test.</param> /// <param name="obj">The object to test.</param>
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
public override bool Equals(object obj) public override bool Equals(object obj) => Behavior.Equals(this, obj);
{
if (!(obj is Color)) return false;
(double a, double r, double g, double b) = ((Color)obj).GetRGB();
return A.EqualsInTolerance(a) && R.EqualsInTolerance(r) && G.EqualsInTolerance(g) && B.EqualsInTolerance(b);
}
/// <summary> /// <summary>
/// Returns a hash code for this <see cref="Color" />. /// Returns a hash code for this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
/// </summary> /// </summary>
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns> /// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
public override int GetHashCode() public override int GetHashCode() => Behavior.GetHashCode(this);
{
unchecked
{
int hashCode = A.GetHashCode();
hashCode = (hashCode * 397) ^ R.GetHashCode();
hashCode = (hashCode * 397) ^ G.GetHashCode();
hashCode = (hashCode * 397) ^ B.GetHashCode();
return hashCode;
}
}
#region Manipulation
/// <summary> /// <summary>
/// Blends a <see cref="Color"/> over this color. /// Blends a <see cref="Color"/> over this color, as defined by the current <see cref="Behavior"/>.
/// </summary> /// </summary>
/// <param name="color">The <see cref="Color"/> to blend.</param> /// <param name="color">The <see cref="Color"/> to blend.</param>
public Color Blend(Color color) public Color Blend(Color color) => Behavior.Blend(this, color);
{
if (color.A.EqualsInTolerance(0)) return this;
if (color.A.EqualsInTolerance(1))
return color;
double resultA = (1.0 - ((1.0 - color.A) * (1.0 - A)));
double resultR = (((color.R * color.A) / resultA) + ((R * A * (1.0 - color.A)) / resultA));
double resultG = (((color.G * color.A) / resultA) + ((G * A * (1.0 - color.A)) / resultA));
double resultB = (((color.B * color.A) / resultA) + ((B * A * (1.0 - color.A)) / resultA));
return new Color(resultA, resultR, resultG, resultB);
}
#endregion
#endregion #endregion

View File

@ -2,6 +2,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=brushes/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=brushes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=color/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=color/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=colorcorrection/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=colorcorrection/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=color_005Cbehaviors/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=decorators/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=decorators/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices_005Cupdate/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices_005Cupdate/@EntryIndexedValue">True</s:Boolean>