25 public partial
struct Colour : IEquatable<Colour>
47 private Colour(
double r,
double g,
double b,
double a)
64 return new Colour(r, g, b, 1);
76 return new Colour(r / 255.0, g / 255.0, b / 255.0, 1);
88 return new Colour(r / 255.0, g / 255.0, b / 255.0, 1);
101 return new Colour(r, g, b, a);
114 return new Colour(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
127 return new Colour(r / 255.0, g / 255.0, b / 255.0, a);
139 return new Colour(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
152 return new Colour(r / 255.0, g / 255.0, b / 255.0, a);
162 return new Colour(colour.r / 255.0, colour.g / 255.0, colour.b / 255.0, colour.a);
174 return this.
Equals((Colour)obj);
181 return col.
R == this.R && col.
G == this.G && col.
B == this.B && col.
A == this.
A;
187 return col1.
R == col2.
R && col1.
G == col2.
G && col1.
B == col2.
B && col1.
A == col2.
A;
193 return col1.
R != col2.
R || col1.
G != col2.
G || col1.
B != col2.
B || col1.
A != col2.
A;
199 return (
int)(this.R * 255 + this.G * 255 * 255 + this.B * 255 * 255 * 255 + this.A * 255 * 255 * 255 * 255);
212 return "#" + ((int)Math.Round(
this.R * 255)).ToString(
"X2") + ((int)Math.Round(
this.G * 255)).ToString(
"X2") + ((int)Math.Round(
this.B * 255)).ToString(
"X2") + ((int)Math.Round(
this.A * 255)).ToString(
"X2");
216 return "#" + ((int)Math.Round(
this.R * 255)).ToString(
"X2") + ((int)Math.Round(
this.G * 255)).ToString(
"X2") + ((int)Math.Round(
this.B * 255)).ToString(
"X2");
227 if (cssString.StartsWith(
"#"))
229 cssString = cssString.Substring(1);
231 if (cssString.Length == 3)
233 byte r =
byte.Parse(cssString.Substring(0, 1) + cssString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);
234 byte g =
byte.Parse(cssString.Substring(1, 1) + cssString.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);
235 byte b =
byte.Parse(cssString.Substring(2, 1) + cssString.Substring(2, 1), System.Globalization.NumberStyles.HexNumber);
239 else if (cssString.Length == 4)
241 byte r =
byte.Parse(cssString.Substring(0, 1) + cssString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);
242 byte g =
byte.Parse(cssString.Substring(1, 1) + cssString.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);
243 byte b =
byte.Parse(cssString.Substring(2, 1) + cssString.Substring(2, 1), System.Globalization.NumberStyles.HexNumber);
244 byte a =
byte.Parse(cssString.Substring(3, 1) + cssString.Substring(3, 1), System.Globalization.NumberStyles.HexNumber);
248 else if (cssString.Length == 6)
250 byte r =
byte.Parse(cssString.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
251 byte g =
byte.Parse(cssString.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
252 byte b =
byte.Parse(cssString.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
256 else if (cssString.Length == 8)
258 byte r =
byte.Parse(cssString.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
259 byte g =
byte.Parse(cssString.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
260 byte b =
byte.Parse(cssString.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
261 byte a =
byte.Parse(cssString.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
270 else if (cssString.StartsWith(
"rgb(") || cssString.StartsWith(
"rgba("))
274 cssString = cssString.Substring(cssString.IndexOf(
"(") + 1).Replace(
")",
"").Replace(
" ",
"");
275 string[] splitCssString = cssString.Split(
',');
277 double R = ParseColourValueOrPercentage(splitCssString[0]);
278 double G = ParseColourValueOrPercentage(splitCssString[1]);
279 double B = ParseColourValueOrPercentage(splitCssString[2]);
283 if (splitCssString.Length == 4)
285 A =
double.Parse(splitCssString[3], System.Globalization.CultureInfo.InvariantCulture);
297 if (StandardColours.TryGetValue(cssString, out
Colour tbr))
308 private static double ParseColourValueOrPercentage(
string value)
310 if (
int.TryParse(value, out
int tbr))
314 else if (value.Contains(
"%"))
316 return double.Parse(value.Replace(
"%",
""), System.Globalization.CultureInfo.InvariantCulture) / 100.0;
320 return double.Parse(value, System.Globalization.CultureInfo.InvariantCulture);
343 return Colour.
FromRgba(original.
R, original.
G, original.
B, (
double)alpha / 255.0);
363 return Colour.
FromRgba(this.R, this.G, this.B, (
double)alpha / 255.0);
370 public (
double X,
double Y,
double Z) ToXYZ()
380 r = Math.Pow((200 *
R + 11) / 211, 2.4);
389 g = Math.Pow((200 *
G + 11) / 211, 2.4);
398 b = Math.Pow((200 *
B + 11) / 211, 2.4);
401 double x = 0.41239080 * r + 0.35758434 * g + 0.18048079 * b;
402 double y = 0.21263901 * r + 0.71516868 * g + 0.07219232 * b;
403 double z = 0.01933082 * r + 0.11919478 * g + 0.95053215 * b;
417 double r = +3.24096994 * x - 1.53738318 * y - 0.49861076 * z;
418 double g = -0.96924364 * x + 1.8759675 * y + 0.04155506 * z;
419 double b = 0.05563008 * x - 0.20397696 * y + 1.05697151 * z;
427 r = (211 * Math.Pow(r, 1 / 2.4) - 11) / 200;
436 g = (211 * Math.Pow(g, 1 / 2.4) - 11) / 200;
445 b = (211 * Math.Pow(b, 1 / 2.4) - 11) / 200;
448 r = Math.Min(Math.Max(0, r), 1);
449 g = Math.Min(Math.Max(0, g), 1);
450 b = Math.Min(Math.Max(0, b), 1);
459 public (
double L,
double a,
double b) ToLab()
463 const double d = 6.0 / 29;
467 return Math.Pow(t, 1.0 / 3);
471 return t / (3 * d * d) + 4.0 / 29;
475 const double xN = 0.950489;
477 const double zN = 1.088840;
479 (
double x,
double y,
double z) = this.ToXYZ();
481 double fY = f(y / yN);
483 double l = 1.16 * fY - 0.16;
484 double a = 5 * (f(x / xN) - fY);
485 double b = 2 * (fY - f(z / zN));
501 const double d = 6.0 / 29;
509 return 3 * d * d * (t - 4.0 / 29);
513 const double xN = 0.950489;
515 const double zN = 1.088840;
517 double x = xN * f((
L + 0.16) / 1.16 + a / 5);
518 double y = yN * f((
L + 0.16) / 1.16);
519 double z = zN * f((
L + 0.16) / 1.16 - b / 2);
528 public (
double H,
double S,
double L) ToHSL()
530 double xMax = Math.Max(Math.Max(
R,
G),
B);
531 double xMin = Math.Min(Math.Min(
R,
G),
B);
533 double l = (xMax + xMin) * 0.5;
543 h = (
G -
B) / (xMax - xMin) / 6;
547 h = (2 + (
B -
R) / (xMax - xMin)) / 6;
551 h = (4 + (
R -
G) / (xMax - xMin)) / 6;
556 if (l == 0 || l == 1)
562 s = (xMax - l) / Math.Min(l, 1 - l);
577 double c = (1 - Math.Abs(2 * l - 1)) * s;
581 double x = c * (1 - Math.Abs((hp % 2) - 1));
628 double m = l - c / 2;