Files
RobustToolbox/Robust.Shared.Maths/Color.cs

1964 lines
70 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
using Robust.Shared.Utility;
using SysVector3 = System.Numerics.Vector3;
using SysVector4 = System.Numerics.Vector4;
#if NETCOREAPP
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#endif
namespace Robust.Shared.Maths
{
/// <summary>
/// Represents a color with 4 floating-point components (R, G, B, A).
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Color : IEquatable<Color>, ISpanFormattable
{
/// <summary>
/// The red component of this Color4 structure.
/// </summary>
public float R;
/// <summary>
/// The green component of this Color4 structure.
/// </summary>
public float G;
/// <summary>
/// The blue component of this Color4 structure.
/// </summary>
public float B;
/// <summary>
/// The alpha component of this Color4 structure.
/// </summary>
public float A;
public readonly byte RByte => (byte) (R * byte.MaxValue);
public readonly byte GByte => (byte) (G * byte.MaxValue);
public readonly byte BByte => (byte) (B * byte.MaxValue);
public readonly byte AByte => (byte) (A * byte.MaxValue);
/// <summary>
/// Constructs a new Color4 structure from the specified components.
/// </summary>
/// <param name="r">The red component of the new Color4 structure.</param>
/// <param name="g">The green component of the new Color4 structure.</param>
/// <param name="b">The blue component of the new Color4 structure.</param>
/// <param name="a">The alpha component of the new Color4 structure.</param>
public Color(float r, float g, float b, float a = 1)
{
R = r;
G = g;
B = b;
A = a;
}
/// <summary>
/// Constructs a new Color4 structure from the specified components.
/// </summary>
/// <param name="r">The red component of the new Color4 structure.</param>
/// <param name="g">The green component of the new Color4 structure.</param>
/// <param name="b">The blue component of the new Color4 structure.</param>
/// <param name="a">The alpha component of the new Color4 structure.</param>
public Color(byte r, byte g, byte b, byte a = 255)
{
R = r / (float) byte.MaxValue;
G = g / (float) byte.MaxValue;
B = b / (float) byte.MaxValue;
A = a / (float) byte.MaxValue;
}
/// <summary>
/// Converts this color to an integer representation with 8 bits per channel.
/// </summary>
/// <returns>A <see cref="System.Int32" /> that represents this instance.</returns>
/// <remarks>
/// This method is intended only for compatibility with System.Drawing. It compresses the color into 8 bits per
/// channel, which means color information is lost.
/// </remarks>
public readonly int ToArgb()
{
var value =
((uint) (A * byte.MaxValue) << 24) |
((uint) (R * byte.MaxValue) << 16) |
((uint) (G * byte.MaxValue) << 8) |
(uint) (B * byte.MaxValue);
return unchecked((int) value);
}
/// <summary>
/// Compares the specified Color4 structures for equality.
/// </summary>
/// <param name="left">The left-hand side of the comparison.</param>
/// <param name="right">The right-hand side of the comparison.</param>
/// <returns>True if left is equal to right; false otherwise.</returns>
public static bool operator ==(Color left, Color right)
{
return left.Equals(right);
}
/// <summary>
/// Compares the specified Color4 structures for inequality.
/// </summary>
/// <param name="left">The left-hand side of the comparison.</param>
/// <param name="right">The right-hand side of the comparison.</param>
/// <returns>True if left is not equal to right; false otherwise.</returns>
public static bool operator !=(Color left, Color right)
{
return !left.Equals(right);
}
/// <summary>
/// Converts the specified System.Drawing.Color to a Color4 structure.
/// </summary>
/// <param name="color">The System.Drawing.Color to convert.</param>
/// <returns>A new Color4 structure containing the converted components.</returns>
public static implicit operator Color(System.Drawing.Color color)
{
return new(color.R, color.G, color.B, color.A);
}
public static implicit operator Color((float r, float g, float b, float a) tuple)
{
return new(tuple.r, tuple.g, tuple.b, tuple.a);
}
public static implicit operator Color((float r, float g, float b) tuple)
{
return new(tuple.r, tuple.g, tuple.b);
}
public readonly void Deconstruct(out float r, out float g, out float b, out float a)
{
r = R;
g = G;
b = B;
a = A;
}
public readonly void Deconstruct(out float r, out float g, out float b)
{
r = R;
g = G;
b = B;
}
/// <summary>
/// Converts the specified Color4 to a System.Drawing.Color structure.
/// </summary>
/// <param name="color">The Color4 to convert.</param>
/// <returns>A new System.Drawing.Color structure containing the converted components.</returns>
public static explicit operator System.Drawing.Color(Color color)
{
return System.Drawing.Color.FromArgb(
(int) (color.A * byte.MaxValue),
(int) (color.R * byte.MaxValue),
(int) (color.G * byte.MaxValue),
(int) (color.B * byte.MaxValue));
}
public static Color FromName(string colorname)
{
return DefaultColors[colorname.ToLower()];
}
public static bool TryFromName(string colorName, out Color color)
{
return DefaultColors.TryGetValue(colorName.ToLower(), out color);
}
public static IEnumerable<KeyValuePair<string, Color>> GetAllDefaultColors()
{
return DefaultColors;
}
/// <summary>
/// Compares whether this Color4 structure is equal to the specified object.
/// </summary>
/// <param name="obj">An object to compare to.</param>
/// <returns>True obj is a Color4 structure with the same components as this Color4; false otherwise.</returns>
public override readonly bool Equals(object? obj)
{
if (!(obj is Color))
return false;
return Equals((Color) obj);
}
/// <summary>
/// Calculates the hash code for this Color4 structure.
/// </summary>
/// <returns>A System.Int32 containing the hash code of this Color4 structure.</returns>
public override readonly int GetHashCode()
{
return ToArgb();
}
/// <summary>
/// Creates a System.String that describes this Color4 structure.
/// </summary>
/// <returns>A System.String that describes this Color4 structure.</returns>
public override readonly string ToString()
{
return $"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}");
}
public readonly Color WithRed(float newR)
{
return new(newR, G, B, A);
}
public readonly Color WithGreen(float newG)
{
return new(R, newG, B, A);
}
public readonly Color WithBlue(float newB)
{
return new(R, G, newB, A);
}
public readonly Color WithAlpha(float newA)
{
return new(R, G, B, newA);
}
public readonly Color WithRed(byte newR)
{
return new((float) newR / byte.MaxValue, G, B, A);
}
public readonly Color WithGreen(byte newG)
{
return new(R, (float) newG / byte.MaxValue, B, A);
}
public readonly Color WithBlue(byte newB)
{
return new(R, G, (float) newB / byte.MaxValue, A);
}
public readonly Color WithAlpha(byte newA)
{
return new(R, G, B, (float) newA / byte.MaxValue);
}
/// <summary>
/// Converts sRGB color values to linear RGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="srgb">
/// Color value to convert in sRGB.
/// </param>
public static Color FromSrgb(Color srgb)
{
float r, g, b;
#if NETCOREAPP
if (srgb.R <= 0.04045f)
r = srgb.R / 12.92f;
else
r = MathF.Pow((srgb.R + 0.055f) / (1.0f + 0.055f), 2.4f);
if (srgb.G <= 0.04045f)
g = srgb.G / 12.92f;
else
g = MathF.Pow((srgb.G + 0.055f) / (1.0f + 0.055f), 2.4f);
if (srgb.B <= 0.04045f)
b = srgb.B / 12.92f;
else
b = MathF.Pow((srgb.B + 0.055f) / (1.0f + 0.055f), 2.4f);
#else
if (srgb.R <= 0.04045f)
r = srgb.R / 12.92f;
else
r = (float) Math.Pow((srgb.R + 0.055f) / (1.0f + 0.055f), 2.4f);
if (srgb.G <= 0.04045f)
g = srgb.G / 12.92f;
else
g = (float) Math.Pow((srgb.G + 0.055f) / (1.0f + 0.055f), 2.4f);
if (srgb.B <= 0.04045f)
b = srgb.B / 12.92f;
else
b = (float) Math.Pow((srgb.B + 0.055f) / (1.0f + 0.055f), 2.4f);
#endif
return new Color(r, g, b, srgb.A);
}
/// <summary>
/// Converts linear RGB color values to sRGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="rgb">Color value to convert.</param>
public static Color ToSrgb(Color rgb)
{
float r, g, b;
#if NETCOREAPP
if (rgb.R <= 0.0031308)
r = 12.92f * rgb.R;
else
r = (1.0f + 0.055f) * MathF.Pow(rgb.R, 1.0f / 2.4f) - 0.055f;
if (rgb.G <= 0.0031308)
g = 12.92f * rgb.G;
else
g = (1.0f + 0.055f) * MathF.Pow(rgb.G, 1.0f / 2.4f) - 0.055f;
if (rgb.B <= 0.0031308)
b = 12.92f * rgb.B;
else
b = (1.0f + 0.055f) * MathF.Pow(rgb.B, 1.0f / 2.4f) - 0.055f;
#else
if (rgb.R <= 0.0031308)
r = 12.92f * rgb.R;
else
r = (1.0f + 0.055f) * (float) Math.Pow(rgb.R, 1.0f / 2.4f) - 0.055f;
if (rgb.G <= 0.0031308)
g = 12.92f * rgb.G;
else
g = (1.0f + 0.055f) * (float) Math.Pow(rgb.G, 1.0f / 2.4f) - 0.055f;
if (rgb.B <= 0.0031308)
b = 12.92f * rgb.B;
else
b = (1.0f + 0.055f) * (float) Math.Pow(rgb.B, 1.0f / 2.4f) - 0.055f;
#endif
return new Color(r, g, b, rgb.A);
}
/// <summary>
/// Converts HSL color values to RGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="hsl">
/// Color value to convert in hue, saturation, lightness (HSL).
/// The X element is Hue (H), the Y element is Saturation (S), the Z element is Lightness (L), and the W element is
/// Alpha (which is copied to the output's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </param>
public static Color FromHsl(Vector4 hsl)
{
var hue = (hsl.X - MathF.Truncate(hsl.X)) * 360.0f;
var saturation = hsl.Y;
var lightness = hsl.Z;
var c = (1.0f - MathF.Abs(2.0f * lightness - 1.0f)) * saturation;
var h = hue / 60.0f;
var X = c * (1.0f - MathF.Abs(h % 2.0f - 1.0f));
float r, g, b;
if (0.0f <= h && h < 1.0f)
{
r = c;
g = X;
b = 0.0f;
}
else if (1.0f <= h && h < 2.0f)
{
r = X;
g = c;
b = 0.0f;
}
else if (2.0f <= h && h < 3.0f)
{
r = 0.0f;
g = c;
b = X;
}
else if (3.0f <= h && h < 4.0f)
{
r = 0.0f;
g = X;
b = c;
}
else if (4.0f <= h && h < 5.0f)
{
r = X;
g = 0.0f;
b = c;
}
else if (5.0f <= h && h < 6.0f)
{
r = c;
g = 0.0f;
b = X;
}
else
{
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
var m = lightness - c / 2.0f;
return new Color(r + m, g + m, b + m, hsl.W);
}
/// <summary>
/// Converts RGB color values to HSL color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// The X element is Hue (H), the Y element is Saturation (S), the Z element is Lightness (L), and the W element is
/// Alpha (a copy of the input's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </returns>
/// <param name="rgb">Color value to convert.</param>
public static Vector4 ToHsl(Color rgb)
{
var max = MathF.Max(rgb.R, MathF.Max(rgb.G, rgb.B));
var min = MathF.Min(rgb.R, MathF.Min(rgb.G, rgb.B));
var c = max - min;
var h = 0.0f;
if (c != 0)
{
if (max == rgb.R)
h = (rgb.G - rgb.B) / c;
else if (max == rgb.G)
h = (rgb.B - rgb.R) / c + 2.0f;
else if (max == rgb.B)
h = (rgb.R - rgb.G) / c + 4.0f;
}
var hue = h / 6.0f;
if (hue < 0.0f)
hue += 1.0f;
var lightness = (max + min) / 2.0f;
var saturation = 0.0f;
if (0.0f != lightness && lightness != 1.0f)
saturation = c / (1.0f - MathF.Abs(2.0f * lightness - 1.0f));
return new Vector4(hue, saturation, lightness, rgb.A);
}
/// <summary>
/// Converts HSV color values to RGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="hsv">
/// Color value to convert in hue, saturation, value (HSV).
/// The X element is Hue (H), the Y element is Saturation (S), the Z element is Value (V), and the W element is Alpha
/// (which is copied to the output's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </param>
public static Color FromHsv(Vector4 hsv)
{
var hue = (hsv.X - MathF.Truncate(hsv.X)) * 360.0f;
var saturation = hsv.Y;
var value = hsv.Z;
var c = value * saturation;
var h = hue / 60.0f;
var x = c * (1.0f - MathF.Abs(h % 2.0f - 1.0f));
float r, g, b;
if (0.0f <= h && h < 1.0f)
{
r = c;
g = x;
b = 0.0f;
}
else if (1.0f <= h && h < 2.0f)
{
r = x;
g = c;
b = 0.0f;
}
else if (2.0f <= h && h < 3.0f)
{
r = 0.0f;
g = c;
b = x;
}
else if (3.0f <= h && h < 4.0f)
{
r = 0.0f;
g = x;
b = c;
}
else if (4.0f <= h && h < 5.0f)
{
r = x;
g = 0.0f;
b = c;
}
else if (5.0f <= h && h < 6.0f)
{
r = c;
g = 0.0f;
b = x;
}
else
{
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
var m = value - c;
return new Color(r + m, g + m, b + m, hsv.W);
}
/// <summary>
/// Converts RGB color values to HSV color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// The X element is Hue (H), the Y element is Saturation (S), the Z element is Value (V), and the W element is Alpha
/// (a copy of the input's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </returns>
/// <param name="rgb">Color value to convert.</param>
public static Vector4 ToHsv(Color rgb)
{
var max = MathF.Max(rgb.R, MathF.Max(rgb.G, rgb.B));
var min = MathF.Min(rgb.R, MathF.Min(rgb.G, rgb.B));
var c = max - min;
var h = 0.0f;
if (c != 0)
{
if (max == rgb.R)
{
h = (rgb.G - rgb.B) / c % 6.0f;
if (h < 0f)
h += 6.0f;
}
else if (max == rgb.G)
h = (rgb.B - rgb.R) / c + 2.0f;
else if (max == rgb.B)
h = (rgb.R - rgb.G) / c + 4.0f;
}
var hue = h * 60.0f / 360.0f;
var saturation = 0.0f;
if (0.0f != max)
saturation = c / max;
return new Vector4(hue, saturation, max, rgb.A);
}
/// <summary>
/// Converts XYZ color values to RGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="xyz">
/// Color value to convert with the trisimulus values of X, Y, and Z in the corresponding element, and the W element
/// with Alpha (which is copied to the output's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </param>
/// <remarks>Uses the CIE XYZ colorspace.</remarks>
public static Color FromXyz(Vector4 xyz)
{
var r = 0.41847f * xyz.X + -0.15866f * xyz.Y + -0.082835f * xyz.Z;
var g = -0.091169f * xyz.X + 0.25243f * xyz.Y + 0.015708f * xyz.Z;
var b = 0.00092090f * xyz.X + -0.0025498f * xyz.Y + 0.17860f * xyz.Z;
return new Color(r, g, b, xyz.W);
}
/// <summary>
/// Converts RGB color values to XYZ color values.
/// </summary>
/// <returns>
/// Returns the converted color value with the trisimulus values of X, Y, and Z in the corresponding element, and the W
/// element with Alpha (a copy of the input's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </returns>
/// <param name="rgb">Color value to convert.</param>
/// <remarks>Uses the CIE XYZ colorspace.</remarks>
public static Vector4 ToXyz(Color rgb)
{
var x = (0.49f * rgb.R + 0.31f * rgb.G + 0.20f * rgb.B) / 0.17697f;
var y = (0.17697f * rgb.R + 0.81240f * rgb.G + 0.01063f * rgb.B) / 0.17697f;
var z = (0.00f * rgb.R + 0.01f * rgb.G + 0.99f * rgb.B) / 0.17697f;
return new Vector4(x, y, z, rgb.A);
}
/// <summary>
/// Converts YCbCr color values to RGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="ycbcr">
/// Color value to convert in Luma-Chrominance (YCbCr) aka YUV.
/// The X element contains Luma (Y, 0.0 to 1.0), the Y element contains Blue-difference chroma (U, -0.5 to 0.5), the Z
/// element contains the Red-difference chroma (V, -0.5 to 0.5), and the W element contains the Alpha (which is copied
/// to the output's Alpha value).
/// </param>
/// <remarks>Converts using ITU-R BT.601/CCIR 601 W(r) = 0.299 W(b) = 0.114 U(max) = 0.436 V(max) = 0.615.</remarks>
public static Color FromYcbcr(Vector4 ycbcr)
{
var r = 1.0f * ycbcr.X + 0.0f * ycbcr.Y + 1.402f * ycbcr.Z;
var g = 1.0f * ycbcr.X + -0.344136f * ycbcr.Y + -0.714136f * ycbcr.Z;
var b = 1.0f * ycbcr.X + 1.772f * ycbcr.Y + 0.0f * ycbcr.Z;
return new Color(r, g, b, ycbcr.W);
}
/// <summary>
/// Converts RGB color values to YUV color values.
/// </summary>
/// <returns>
/// Returns the converted color value in Luma-Chrominance (YCbCr) aka YUV.
/// The X element contains Luma (Y, 0.0 to 1.0), the Y element contains Blue-difference chroma (U, -0.5 to 0.5), the Z
/// element contains the Red-difference chroma (V, -0.5 to 0.5), and the W element contains the Alpha (a copy of the
/// input's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </returns>
/// <param name="rgb">Color value to convert.</param>
/// <remarks>Converts using ITU-R BT.601/CCIR 601 W(r) = 0.299 W(b) = 0.114 U(max) = 0.436 V(max) = 0.615.</remarks>
public static Vector4 ToYcbcr(Color rgb)
{
var y = 0.299f * rgb.R + 0.587f * rgb.G + 0.114f * rgb.B;
var u = -0.168736f * rgb.R + -0.331264f * rgb.G + 0.5f * rgb.B;
var v = 0.5f * rgb.R + -0.418688f * rgb.G + -0.081312f * rgb.B;
return new Vector4(y, u, v, rgb.A);
}
/// <summary>
/// Converts HCY color values to RGB color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// </returns>
/// <param name="hcy">
/// Color value to convert in hue, chroma, luminance (HCY).
/// The X element is Hue (H), the Y element is Chroma (C), the Z element is luminance (Y), and the W element is Alpha
/// (which is copied to the output's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </param>
public static Color FromHcy(Vector4 hcy)
{
var hue = hcy.X * 360.0f;
var c = hcy.Y;
var luminance = hcy.Z;
var h = hue / 60.0f;
var x = c * (1.0f - MathF.Abs(h % 2.0f - 1.0f));
float r, g, b;
if (0.0f <= h && h < 1.0f)
{
r = c;
g = x;
b = 0.0f;
}
else if (1.0f <= h && h < 2.0f)
{
r = x;
g = c;
b = 0.0f;
}
else if (2.0f <= h && h < 3.0f)
{
r = 0.0f;
g = c;
b = x;
}
else if (3.0f <= h && h < 4.0f)
{
r = 0.0f;
g = x;
b = c;
}
else if (4.0f <= h && h < 5.0f)
{
r = x;
g = 0.0f;
b = c;
}
else if (5.0f <= h && h < 6.0f)
{
r = c;
g = 0.0f;
b = x;
}
else
{
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
var m = luminance - (0.30f * r + 0.59f * g + 0.11f * b);
return new Color(r + m, g + m, b + m, hcy.W);
}
/// <summary>
/// Converts RGB color values to HCY color values.
/// </summary>
/// <returns>
/// Returns the converted color value.
/// The X element is Hue (H), the Y element is Chroma (C), the Z element is luminance (Y), and the W element is Alpha
/// (a copy of the input's Alpha value).
/// Each has a range of 0.0 to 1.0.
/// </returns>
/// <param name="rgb">Color value to convert.</param>
public static Vector4 ToHcy(Color rgb)
{
var max = MathF.Max(rgb.R, MathF.Max(rgb.G, rgb.B));
var min = MathF.Min(rgb.R, MathF.Min(rgb.G, rgb.B));
var c = max - min;
var h = 0.0f;
if (max == rgb.R)
{
h = (rgb.G - rgb.B) / c % 6.0f;
if (h < 0f)
h += 6.0f;
}
else if (max == rgb.G)
h = (rgb.B - rgb.R) / c + 2.0f;
else if (max == rgb.B)
h = (rgb.R - rgb.G) / c + 4.0f;
var hue = h * 60.0f / 360.0f;
var luminance = 0.30f * rgb.R + 0.59f * rgb.G + 0.11f * rgb.B;
return new Vector4(hue, c, luminance, rgb.A);
}
public static Vector4 ToCmyk(Color rgb)
{
var (r, g, b) = rgb;
var k = 1 - MathF.Max(r, MathF.Max(g, b));
var c = (1 - r - k) / (1 - k);
var m = (1 - g - k) / (1 - k);
var y = (1 - b - k) / (1 - k);
return (c, m, y, k);
}
public static Color FromCmyk(Vector4 cmyk)
{
var (c, m, y, k) = cmyk;
var r = (1 - c) * (1 - k);
var g = (1 - m) * (1 - k);
var b = (1 - y) * (1 - k);
return (r, g, b);
}
/// <summary>
/// Interpolate two colors with a lambda, AKA returning the two colors combined with a ratio of
/// <paramref name="λ" />.
/// </summary>
/// <param name="α"></param>
/// <param name="β"></param>
/// <param name="λ">
/// A value ranging from 0-1. The higher the value the more is taken from <paramref name="β" />,
/// with 0.5 being 50% of both colors, 0.25 being 25% of <paramref name="β" /> and 75%
/// <paramref name="α" />.
/// </param>
public static Color InterpolateBetween(Color α, Color β, float λ)
{
if (Sse.IsSupported && Fma.IsSupported)
{
var vecA = Unsafe.As<Color, Vector128<float>>(ref α);
var vecB = Unsafe.As<Color, Vector128<float>>(ref β);
vecB = Fma.MultiplyAdd(Sse.Subtract(vecB, vecA), Vector128.Create(λ), vecA);
return Unsafe.As<Vector128<float>, Color>(ref vecB);
}
ref var svA = ref Unsafe.As<Color, SysVector4>(ref α);
ref var svB = ref Unsafe.As<Color, SysVector4>(ref β);
var res = SysVector4.Lerp(svA, svB, λ);
return Unsafe.As<SysVector4, Color>(ref res);
}
public static Color? TryFromHex(ReadOnlySpan<char> hexColor)
{
if (hexColor.Length <= 0 || hexColor[0] != '#') return null;
if (hexColor.Length == 9)
{
if (!byte.TryParse(hexColor[1..3], NumberStyles.HexNumber, null, out var r)) return null;
if (!byte.TryParse(hexColor[3..5], NumberStyles.HexNumber, null, out var g)) return null;
if (!byte.TryParse(hexColor[5..7], NumberStyles.HexNumber, null, out var b)) return null;
if (!byte.TryParse(hexColor[7..9], NumberStyles.HexNumber, null, out var a)) return null;
return new Color(r, g, b, a);
}
if (hexColor.Length == 7)
{
if (!byte.TryParse(hexColor[1..3], NumberStyles.HexNumber, null, out var r)) return null;
if (!byte.TryParse(hexColor[3..5], NumberStyles.HexNumber, null, out var g)) return null;
if (!byte.TryParse(hexColor[5..7], NumberStyles.HexNumber, null, out var b)) return null;
return new Color(r, g, b);
}
static bool ParseDup(char chr, out byte value)
{
Span<char> buf = stackalloc char[2];
buf[0] = chr;
buf[1] = chr;
return byte.TryParse(buf, NumberStyles.HexNumber, null, out value);
}
if (hexColor.Length == 5)
{
if (!ParseDup(hexColor[1], out var rByte)) return null;
if (!ParseDup(hexColor[2], out var gByte)) return null;
if (!ParseDup(hexColor[3], out var bByte)) return null;
if (!ParseDup(hexColor[4], out var aByte)) return null;
return new Color(rByte, gByte, bByte, aByte);
}
if (hexColor.Length == 4)
{
if (!ParseDup(hexColor[1], out var rByte)) return null;
if (!ParseDup(hexColor[2], out var gByte)) return null;
if (!ParseDup(hexColor[3], out var bByte)) return null;
return new Color(rByte, gByte, bByte);
}
return null;
}
public static Color FromHex(ReadOnlySpan<char> hexColor, Color? fallback = null)
{
var color = TryFromHex(hexColor);
if (color.HasValue)
return color.Value;
if (fallback.HasValue)
return fallback.Value;
throw new ArgumentException($"Invalid color code \"{new string(hexColor)}\" and no fallback provided.", nameof(hexColor));
}
public static Color FromXaml(string name)
{
var color = TryFromHex(name);
if (color != null)
return color.Value;
if (TryFromName(name, out var namedColor))
return namedColor;
throw new ArgumentException($"Invalid XAML color name: '{name}'");
}
public static Color Blend(Color dstColor, Color srcColor, BlendFactor dstFactor, BlendFactor srcFactor)
{
var dst = new SysVector3(dstColor.R, dstColor.G, dstColor.B);
var src = new SysVector3(srcColor.R, srcColor.G, srcColor.B);
var ret = new SysVector3();
switch (dstFactor)
{
case BlendFactor.Zero:
break;
case BlendFactor.One:
ret = dst;
break;
case BlendFactor.SrcColor:
ret = dst * src;
break;
case BlendFactor.OneMinusSrcColor:
ret = dst * (SysVector3.One - src);
break;
case BlendFactor.DstColor:
ret = dst * dst;
break;
case BlendFactor.OneMinusDstColor:
ret = dst * (SysVector3.One - dst);
break;
case BlendFactor.SrcAlpha:
ret = dst * srcColor.A;
break;
case BlendFactor.OneMinusSrcAlpha:
ret = dst * (1 - srcColor.A);
break;
case BlendFactor.DstAlpha:
ret = dst * dstColor.A;
break;
case BlendFactor.OneMinusDstAlpha:
ret = dst * (1 - dstColor.A);
break;
default:
throw new NotImplementedException();
}
switch (srcFactor)
{
case BlendFactor.Zero:
break;
case BlendFactor.One:
ret += src;
break;
case BlendFactor.SrcColor:
ret += src * src;
break;
case BlendFactor.OneMinusSrcColor:
ret += src * (SysVector3.One - src);
break;
case BlendFactor.DstColor:
ret += src * dst;
break;
case BlendFactor.OneMinusDstColor:
ret += src * (SysVector3.One - dst);
break;
case BlendFactor.SrcAlpha:
ret += src * srcColor.A;
break;
case BlendFactor.OneMinusSrcAlpha:
ret += src * (1 - srcColor.A);
break;
case BlendFactor.DstAlpha:
ret += src * dstColor.A;
break;
case BlendFactor.OneMinusDstAlpha:
ret += src * (1 - dstColor.A);
break;
default:
throw new NotImplementedException();
}
return new Color(ret.X, ret.Y, ret.Z, MathF.Min(1, dstColor.A + dstColor.A * srcColor.A));
}
/// <summary>
/// Component wise multiplication of two colors.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static Color operator *(Color a, Color b)
{
return new(a.R * b.R, a.G * b.G, a.B * b.B, a.A * b.A);
}
public readonly string ToHex()
{
var hexColor = 0;
hexColor += RByte << 24;
hexColor += GByte << 16;
hexColor += BByte << 8;
hexColor += AByte;
return $"#{hexColor:X8}";
}
public readonly string ToHexNoAlpha()
{
var hexColor = 0;
hexColor += RByte << 16;
hexColor += GByte << 8;
hexColor += BByte;
return $"#{hexColor:X6}";
}
/// <summary>
/// Compares whether this Color4 structure is equal to the specified Color4.
/// </summary>
/// <param name="other">The Color4 structure to compare to.</param>
/// <returns>True if both Color4 structures contain the same components; false otherwise.</returns>
public readonly bool Equals(Color other)
{
return
MathHelper.CloseToPercent(R, other.R) &&
MathHelper.CloseToPercent(G, other.G) &&
MathHelper.CloseToPercent(B, other.B) &&
MathHelper.CloseToPercent(A, other.A);
}
[PublicAPI]
public enum BlendFactor : byte
{
Zero,
One,
SrcColor,
OneMinusSrcColor,
DstColor,
OneMinusDstColor,
SrcAlpha,
OneMinusSrcAlpha,
DstAlpha,
OneMinusDstAlpha,
}
#region Static Colors
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 255, 255, 0).
/// </summary>
public static Color Transparent => new(255, 255, 255, 0);
/// <summary>
/// Gets the system color with (R, G, B, A) = (240, 248, 255, 255).
/// </summary>
public static Color AliceBlue => new(240, 248, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (250, 235, 215, 255).
/// </summary>
public static Color AntiqueWhite => new(250, 235, 215, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 255, 255, 255).
/// </summary>
public static Color Aqua => new(0, 255, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (127, 255, 212, 255).
/// </summary>
public static Color Aquamarine => new(127, 255, 212, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (240, 255, 255, 255).
/// </summary>
public static Color Azure => new(240, 255, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (245, 245, 220, 255).
/// </summary>
public static Color Beige => new(245, 245, 220, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 228, 196, 255).
/// </summary>
public static Color Bisque => new(255, 228, 196, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 0, 0, 255).
/// </summary>
public static Color Black => new(0, 0, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 235, 205, 255).
/// </summary>
public static Color BlanchedAlmond => new(255, 235, 205, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 0, 255, 255).
/// </summary>
public static Color Blue => new(0, 0, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (138, 43, 226, 255).
/// </summary>
public static Color BlueViolet => new(138, 43, 226, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (165, 42, 42, 255).
/// </summary>
public static Color Brown => new(165, 42, 42, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (222, 184, 135, 255).
/// </summary>
public static Color BurlyWood => new(222, 184, 135, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (95, 158, 160, 255).
/// </summary>
public static Color CadetBlue => new(95, 158, 160, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (127, 255, 0, 255).
/// </summary>
public static Color Chartreuse => new(127, 255, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (210, 105, 30, 255).
/// </summary>
public static Color Chocolate => new(210, 105, 30, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 127, 80, 255).
/// </summary>
public static Color Coral => new(255, 127, 80, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (100, 149, 237, 255).
/// </summary>
public static Color CornflowerBlue => new(100, 149, 237, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 248, 220, 255).
/// </summary>
public static Color Cornsilk => new(255, 248, 220, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (220, 20, 60, 255).
/// </summary>
public static Color Crimson => new(220, 20, 60, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 255, 255, 255).
/// </summary>
public static Color Cyan => new(0, 255, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 0, 139, 255).
/// </summary>
public static Color DarkBlue => new(0, 0, 139, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 139, 139, 255).
/// </summary>
public static Color DarkCyan => new(0, 139, 139, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (184, 134, 11, 255).
/// </summary>
public static Color DarkGoldenrod => new(184, 134, 11, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (169, 169, 169, 255).
/// </summary>
public static Color DarkGray => new(169, 169, 169, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 100, 0, 255).
/// </summary>
public static Color DarkGreen => new(0, 100, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (189, 183, 107, 255).
/// </summary>
public static Color DarkKhaki => new(189, 183, 107, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (139, 0, 139, 255).
/// </summary>
public static Color DarkMagenta => new(139, 0, 139, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (85, 107, 47, 255).
/// </summary>
public static Color DarkOliveGreen => new(85, 107, 47, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 140, 0, 255).
/// </summary>
public static Color DarkOrange => new(255, 140, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (153, 50, 204, 255).
/// </summary>
public static Color DarkOrchid => new(153, 50, 204, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (139, 0, 0, 255).
/// </summary>
public static Color DarkRed => new(139, 0, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (233, 150, 122, 255).
/// </summary>
public static Color DarkSalmon => new(233, 150, 122, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (143, 188, 143, 255).
/// Previously (R, G, B, A) = (143, 188, 139, 255) before .NET 5.
/// </summary>
public static Color DarkSeaGreen => new(143, 188, 143, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (72, 61, 139, 255).
/// </summary>
public static Color DarkSlateBlue => new(72, 61, 139, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (47, 79, 79, 255).
/// </summary>
public static Color DarkSlateGray => new(47, 79, 79, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 206, 209, 255).
/// </summary>
public static Color DarkTurquoise => new(0, 206, 209, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (148, 0, 211, 255).
/// </summary>
public static Color DarkViolet => new(148, 0, 211, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 20, 147, 255).
/// </summary>
public static Color DeepPink => new(255, 20, 147, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 191, 255, 255).
/// </summary>
public static Color DeepSkyBlue => new(0, 191, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (105, 105, 105, 255).
/// </summary>
public static Color DimGray => new(105, 105, 105, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (30, 144, 255, 255).
/// </summary>
public static Color DodgerBlue => new(30, 144, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (178, 34, 34, 255).
/// </summary>
public static Color Firebrick => new(178, 34, 34, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 250, 240, 255).
/// </summary>
public static Color FloralWhite => new(255, 250, 240, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (34, 139, 34, 255).
/// </summary>
public static Color ForestGreen => new(34, 139, 34, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 0, 255, 255).
/// </summary>
public static Color Fuchsia => new(255, 0, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (220, 220, 220, 255).
/// </summary>
public static Color Gainsboro => new(220, 220, 220, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (248, 248, 255, 255).
/// </summary>
public static Color GhostWhite => new(248, 248, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 215, 0, 255).
/// </summary>
public static Color Gold => new(255, 215, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (218, 165, 32, 255).
/// </summary>
public static Color Goldenrod => new(218, 165, 32, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (128, 128, 128, 255).
/// </summary>
public static Color Gray => new(128, 128, 128, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 128, 0, 255).
/// </summary>
public static Color Green => new(0, 128, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (173, 255, 47, 255).
/// </summary>
public static Color GreenYellow => new(173, 255, 47, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (240, 255, 240, 255).
/// </summary>
public static Color Honeydew => new(240, 255, 240, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 105, 180, 255).
/// </summary>
public static Color HotPink => new(255, 105, 180, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (205, 92, 92, 255).
/// </summary>
public static Color IndianRed => new(205, 92, 92, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (75, 0, 130, 255).
/// </summary>
public static Color Indigo => new(75, 0, 130, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 255, 240, 255).
/// </summary>
public static Color Ivory => new(255, 255, 240, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (240, 230, 140, 255).
/// </summary>
public static Color Khaki => new(240, 230, 140, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (230, 230, 250, 255).
/// </summary>
public static Color Lavender => new(230, 230, 250, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 240, 245, 255).
/// </summary>
public static Color LavenderBlush => new(255, 240, 245, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (124, 252, 0, 255).
/// </summary>
public static Color LawnGreen => new(124, 252, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 250, 205, 255).
/// </summary>
public static Color LemonChiffon => new(255, 250, 205, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (173, 216, 230, 255).
/// </summary>
public static Color LightBlue => new(173, 216, 230, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (240, 128, 128, 255).
/// </summary>
public static Color LightCoral => new(240, 128, 128, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (224, 255, 255, 255).
/// </summary>
public static Color LightCyan => new(224, 255, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (250, 250, 210, 255).
/// </summary>
public static Color LightGoldenrodYellow => new(250, 250, 210, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (144, 238, 144, 255).
/// </summary>
public static Color LightGreen => new(144, 238, 144, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (211, 211, 211, 255).
/// </summary>
public static Color LightGray => new(211, 211, 211, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 182, 193, 255).
/// </summary>
public static Color LightPink => new(255, 182, 193, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 160, 122, 255).
/// </summary>
public static Color LightSalmon => new(255, 160, 122, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (32, 178, 170, 255).
/// </summary>
public static Color LightSeaGreen => new(32, 178, 170, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (135, 206, 250, 255).
/// </summary>
public static Color LightSkyBlue => new(135, 206, 250, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (119, 136, 153, 255).
/// </summary>
public static Color LightSlateGray => new(119, 136, 153, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (176, 196, 222, 255).
/// </summary>
public static Color LightSteelBlue => new(176, 196, 222, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 255, 224, 255).
/// </summary>
public static Color LightYellow => new(255, 255, 224, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 255, 0, 255).
/// </summary>
public static Color Lime => new(0, 255, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (50, 205, 50, 255).
/// </summary>
public static Color LimeGreen => new(50, 205, 50, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (250, 240, 230, 255).
/// </summary>
public static Color Linen => new(250, 240, 230, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 0, 255, 255).
/// </summary>
public static Color Magenta => new(255, 0, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (128, 0, 0, 255).
/// </summary>
public static Color Maroon => new(128, 0, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (102, 205, 170, 255).
/// </summary>
public static Color MediumAquamarine => new(102, 205, 170, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 0, 205, 255).
/// </summary>
public static Color MediumBlue => new(0, 0, 205, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (186, 85, 211, 255).
/// </summary>
public static Color MediumOrchid => new(186, 85, 211, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (147, 112, 219, 255).
/// </summary>
public static Color MediumPurple => new(147, 112, 219, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (60, 179, 113, 255).
/// </summary>
public static Color MediumSeaGreen => new(60, 179, 113, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (123, 104, 238, 255).
/// </summary>
public static Color MediumSlateBlue => new(123, 104, 238, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 250, 154, 255).
/// </summary>
public static Color MediumSpringGreen => new(0, 250, 154, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (72, 209, 204, 255).
/// </summary>
public static Color MediumTurquoise => new(72, 209, 204, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (199, 21, 133, 255).
/// </summary>
public static Color MediumVioletRed => new(199, 21, 133, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (25, 25, 112, 255).
/// </summary>
public static Color MidnightBlue => new(25, 25, 112, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (245, 255, 250, 255).
/// </summary>
public static Color MintCream => new(245, 255, 250, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 228, 225, 255).
/// </summary>
public static Color MistyRose => new(255, 228, 225, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 228, 181, 255).
/// </summary>
public static Color Moccasin => new(255, 228, 181, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 222, 173, 255).
/// </summary>
public static Color NavajoWhite => new(255, 222, 173, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 0, 128, 255).
/// </summary>
public static Color Navy => new(0, 0, 128, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (253, 245, 230, 255).
/// </summary>
public static Color OldLace => new(253, 245, 230, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (128, 128, 0, 255).
/// </summary>
public static Color Olive => new(128, 128, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (107, 142, 35, 255).
/// </summary>
public static Color OliveDrab => new(107, 142, 35, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 165, 0, 255).
/// </summary>
public static Color Orange => new(255, 165, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 69, 0, 255).
/// </summary>
public static Color OrangeRed => new(255, 69, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (218, 112, 214, 255).
/// </summary>
public static Color Orchid => new(218, 112, 214, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (238, 232, 170, 255).
/// </summary>
public static Color PaleGoldenrod => new(238, 232, 170, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (152, 251, 152, 255).
/// </summary>
public static Color PaleGreen => new(152, 251, 152, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (175, 238, 238, 255).
/// </summary>
public static Color PaleTurquoise => new(175, 238, 238, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (219, 112, 147, 255).
/// </summary>
public static Color PaleVioletRed => new(219, 112, 147, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 239, 213, 255).
/// </summary>
public static Color PapayaWhip => new(255, 239, 213, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 218, 185, 255).
/// </summary>
public static Color PeachPuff => new(255, 218, 185, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (205, 133, 63, 255).
/// </summary>
public static Color Peru => new(205, 133, 63, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 192, 203, 255).
/// </summary>
public static Color Pink => new(255, 192, 203, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (221, 160, 221, 255).
/// </summary>
public static Color Plum => new(221, 160, 221, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (176, 224, 230, 255).
/// </summary>
public static Color PowderBlue => new(176, 224, 230, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (128, 0, 128, 255).
/// </summary>
public static Color Purple => new(128, 0, 128, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 0, 0, 255).
/// </summary>
public static Color Red => new(255, 0, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (188, 143, 143, 255).
/// </summary>
public static Color RosyBrown => new(188, 143, 143, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (65, 105, 225, 255).
/// </summary>
public static Color RoyalBlue => new(65, 105, 225, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (204, 71, 120, 255).
/// </summary>
public static Color Ruber => new(204, 71, 120, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (139, 69, 19, 255).
/// </summary>
public static Color SaddleBrown => new(139, 69, 19, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (250, 128, 114, 255).
/// </summary>
public static Color Salmon => new(250, 128, 114, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (244, 164, 96, 255).
/// </summary>
public static Color SandyBrown => new(244, 164, 96, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 66, 153, 255).
/// </summary>
public static Color SeaBlue => new(0, 66, 153, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (46, 139, 87, 255).
/// </summary>
public static Color SeaGreen => new(46, 139, 87, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 245, 238, 255).
/// </summary>
public static Color SeaShell => new(255, 245, 238, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (160, 82, 45, 255).
/// </summary>
public static Color Sienna => new(160, 82, 45, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (192, 192, 192, 255).
/// </summary>
public static Color Silver => new(192, 192, 192, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (135, 206, 235, 255).
/// </summary>
public static Color SkyBlue => new(135, 206, 235, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (106, 90, 205, 255).
/// </summary>
public static Color SlateBlue => new(106, 90, 205, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (112, 128, 144, 255).
/// </summary>
public static Color SlateGray => new(112, 128, 144, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 250, 250, 255).
/// </summary>
public static Color Snow => new(255, 250, 250, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 255, 127, 255).
/// </summary>
public static Color SpringGreen => new(0, 255, 127, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (70, 130, 180, 255).
/// </summary>
public static Color SteelBlue => new(70, 130, 180, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (210, 180, 140, 255).
/// </summary>
public static Color Tan => new(210, 180, 140, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (0, 128, 128, 255).
/// </summary>
public static Color Teal => new(0, 128, 128, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (216, 191, 216, 255).
/// </summary>
public static Color Thistle => new(216, 191, 216, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 99, 71, 255).
/// </summary>
public static Color Tomato => new(255, 99, 71, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (64, 224, 208, 255).
/// </summary>
public static Color Turquoise => new(64, 224, 208, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (238, 130, 238, 255).
/// </summary>
public static Color Violet => new(238, 130, 238, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (126, 3, 168, 255).
/// </summary>
public static Color BetterViolet => new(126, 3, 168, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 153, 0, 255).
/// </summary>
public static Color VividGamboge => new(255, 153, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (245, 222, 179, 255).
/// </summary>
public static Color Wheat => new(245, 222, 179, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 255, 255, 255).
/// </summary>
public static Color White => new(255, 255, 255, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (245, 245, 245, 255).
/// </summary>
public static Color WhiteSmoke => new(245, 245, 245, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (255, 255, 0, 255).
/// </summary>
public static Color Yellow => new(255, 255, 0, 255);
/// <summary>
/// Gets the system color with (R, G, B, A) = (154, 205, 50, 255).
/// </summary>
public static Color YellowGreen => new(154, 205, 50, 255);
private static readonly FrozenDictionary<string, Color> DefaultColors = new Dictionary<string, Color>()
{
["transparent"] = Transparent,
["aliceblue"] = AliceBlue,
["antiquewhite"] = AntiqueWhite,
["aqua"] = Aqua,
["aquamarine"] = Aquamarine,
["azure"] = Azure,
["beige"] = Beige,
["betterviolet"] = BetterViolet,
["bisque"] = Bisque,
["black"] = Black,
["blanchedalmond"] = BlanchedAlmond,
["blue"] = Blue,
["blueviolet"] = BlueViolet,
["brown"] = Brown,
["burlywood"] = BurlyWood,
["cadetblue"] = CadetBlue,
["chartreuse"] = Chartreuse,
["chocolate"] = Chocolate,
["coral"] = Coral,
["cornflowerblue"] = CornflowerBlue,
["cornsilk"] = Cornsilk,
["crimson"] = Crimson,
["cyan"] = Cyan,
["darkblue"] = DarkBlue,
["darkcyan"] = DarkCyan,
["darkgoldenrod"] = DarkGoldenrod,
["darkgray"] = DarkGray,
["darkgreen"] = DarkGreen,
["darkkhaki"] = DarkKhaki,
["darkmagenta"] = DarkMagenta,
["darkolivegreen"] = DarkOliveGreen,
["darkorange"] = DarkOrange,
["darkorchid"] = DarkOrchid,
["darkred"] = DarkRed,
["darksalmon"] = DarkSalmon,
["darkseagreen"] = DarkSeaGreen,
["darkslateblue"] = DarkSlateBlue,
["darkslategray"] = DarkSlateGray,
["darkturquoise"] = DarkTurquoise,
["darkviolet"] = DarkViolet,
["deeppink"] = DeepPink,
["deepskyblue"] = DeepSkyBlue,
["dimgray"] = DimGray,
["dodgerblue"] = DodgerBlue,
["firebrick"] = Firebrick,
["floralwhite"] = FloralWhite,
["forestgreen"] = ForestGreen,
["fuchsia"] = Fuchsia,
["gainsboro"] = Gainsboro,
["ghostwhite"] = GhostWhite,
["gold"] = Gold,
["goldenrod"] = Goldenrod,
["gray"] = Gray,
["green"] = Green,
["greenyellow"] = GreenYellow,
["honeydew"] = Honeydew,
["hotpink"] = HotPink,
["indianred"] = IndianRed,
["indigo"] = Indigo,
["ivory"] = Ivory,
["khaki"] = Khaki,
["lavender"] = Lavender,
["lavenderblush"] = LavenderBlush,
["lawngreen"] = LawnGreen,
["lemonchiffon"] = LemonChiffon,
["lightblue"] = LightBlue,
["lightcoral"] = LightCoral,
["lightcyan"] = LightCyan,
["lightgoldenrodyellow"] = LightGoldenrodYellow,
["lightgreen"] = LightGreen,
["lightgray"] = LightGray,
["lightpink"] = LightPink,
["lightsalmon"] = LightSalmon,
["lightseagreen"] = LightSeaGreen,
["lightskyblue"] = LightSkyBlue,
["lightslategray"] = LightSlateGray,
["lightsteelblue"] = LightSteelBlue,
["lightyellow"] = LightYellow,
["lime"] = Lime,
["limegreen"] = LimeGreen,
["linen"] = Linen,
["magenta"] = Magenta,
["maroon"] = Maroon,
["mediumaquamarine"] = MediumAquamarine,
["mediumblue"] = MediumBlue,
["mediumorchid"] = MediumOrchid,
["mediumpurple"] = MediumPurple,
["mediumseagreen"] = MediumSeaGreen,
["mediumslateblue"] = MediumSlateBlue,
["mediumspringgreen"] = MediumSpringGreen,
["mediumturquoise"] = MediumTurquoise,
["mediumvioletred"] = MediumVioletRed,
["midnightblue"] = MidnightBlue,
["mintcream"] = MintCream,
["mistyrose"] = MistyRose,
["moccasin"] = Moccasin,
["navajowhite"] = NavajoWhite,
["navy"] = Navy,
["oldlace"] = OldLace,
["olive"] = Olive,
["olivedrab"] = OliveDrab,
["orange"] = Orange,
["orangered"] = OrangeRed,
["orchid"] = Orchid,
["palegoldenrod"] = PaleGoldenrod,
["palegreen"] = PaleGreen,
["paleturquoise"] = PaleTurquoise,
["palevioletred"] = PaleVioletRed,
["papayawhip"] = PapayaWhip,
["peachpuff"] = PeachPuff,
["peru"] = Peru,
["pink"] = Pink,
["plum"] = Plum,
["powderblue"] = PowderBlue,
["purple"] = Purple,
["red"] = Red,
["rosybrown"] = RosyBrown,
["royalblue"] = RoyalBlue,
["ruber"] = Ruber,
["saddlebrown"] = SaddleBrown,
["salmon"] = Salmon,
["sandybrown"] = SandyBrown,
["seablue"] = SeaBlue,
["seagreen"] = SeaGreen,
["seashell"] = SeaShell,
["sienna"] = Sienna,
["silver"] = Silver,
["skyblue"] = SkyBlue,
["slateblue"] = SlateBlue,
["slategray"] = SlateGray,
["snow"] = Snow,
["springgreen"] = SpringGreen,
["steelblue"] = SteelBlue,
["tan"] = Tan,
["teal"] = Teal,
["thistle"] = Thistle,
["tomato"] = Tomato,
["turquoise"] = Turquoise,
["violet"] = Violet,
["vividgamboge"] = VividGamboge,
["wheat"] = Wheat,
["white"] = White,
["whitesmoke"] = WhiteSmoke,
["yellow"] = Yellow,
["yellowgreen"] = YellowGreen,
}.ToFrozenDictionary();
#endregion
private static readonly FrozenDictionary<Color, string> DefaultColorsInverted =
DefaultColors.ToLookup(pair => pair.Value).ToFrozenDictionary(i => i.Key, i => i.First().Key);
public readonly string? Name()
{
return DefaultColorsInverted.TryGetValue(this, out var name) ? name : null;
}
public static bool TryParse(string input, out Color color)
{
if (TryFromName(input, out color))
return true;
var nullableColor = TryFromHex(input);
if (nullableColor != null)
{
color = nullableColor.Value;
return true;
}
return false;
}
}
}