1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 using System.Diagnostics.CodeAnalysis;
7 using System.Numerics.Hashing;
8 
9 namespace System.Drawing
10 {
11     [DebuggerDisplay("{NameAndARGBValue}")]
12     [Serializable]
13 #if !MONO
14     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
15 #endif
16     public readonly struct Color : IEquatable<Color>
17     {
18         public static readonly Color Empty = new Color();
19 
20         // -------------------------------------------------------------------
21         //  static list of "web" colors...
22         //
23         public static Color Transparent => new Color(KnownColor.Transparent);
24 
25         public static Color AliceBlue => new Color(KnownColor.AliceBlue);
26 
27         public static Color AntiqueWhite => new Color(KnownColor.AntiqueWhite);
28 
29         public static Color Aqua => new Color(KnownColor.Aqua);
30 
31         public static Color Aquamarine => new Color(KnownColor.Aquamarine);
32 
33         public static Color Azure => new Color(KnownColor.Azure);
34 
35         public static Color Beige => new Color(KnownColor.Beige);
36 
37         public static Color Bisque => new Color(KnownColor.Bisque);
38 
39         public static Color Black => new Color(KnownColor.Black);
40 
41         public static Color BlanchedAlmond => new Color(KnownColor.BlanchedAlmond);
42 
43         public static Color Blue => new Color(KnownColor.Blue);
44 
45         public static Color BlueViolet => new Color(KnownColor.BlueViolet);
46 
47         public static Color Brown => new Color(KnownColor.Brown);
48 
49         public static Color BurlyWood => new Color(KnownColor.BurlyWood);
50 
51         public static Color CadetBlue => new Color(KnownColor.CadetBlue);
52 
53         public static Color Chartreuse => new Color(KnownColor.Chartreuse);
54 
55         public static Color Chocolate => new Color(KnownColor.Chocolate);
56 
57         public static Color Coral => new Color(KnownColor.Coral);
58 
59         public static Color CornflowerBlue => new Color(KnownColor.CornflowerBlue);
60 
61         public static Color Cornsilk => new Color(KnownColor.Cornsilk);
62 
63         public static Color Crimson => new Color(KnownColor.Crimson);
64 
65         public static Color Cyan => new Color(KnownColor.Cyan);
66 
67         public static Color DarkBlue => new Color(KnownColor.DarkBlue);
68 
69         public static Color DarkCyan => new Color(KnownColor.DarkCyan);
70 
71         public static Color DarkGoldenrod => new Color(KnownColor.DarkGoldenrod);
72 
73         public static Color DarkGray => new Color(KnownColor.DarkGray);
74 
75         public static Color DarkGreen => new Color(KnownColor.DarkGreen);
76 
77         public static Color DarkKhaki => new Color(KnownColor.DarkKhaki);
78 
79         public static Color DarkMagenta => new Color(KnownColor.DarkMagenta);
80 
81         public static Color DarkOliveGreen => new Color(KnownColor.DarkOliveGreen);
82 
83         public static Color DarkOrange => new Color(KnownColor.DarkOrange);
84 
85         public static Color DarkOrchid => new Color(KnownColor.DarkOrchid);
86 
87         public static Color DarkRed => new Color(KnownColor.DarkRed);
88 
89         public static Color DarkSalmon => new Color(KnownColor.DarkSalmon);
90 
91         public static Color DarkSeaGreen => new Color(KnownColor.DarkSeaGreen);
92 
93         public static Color DarkSlateBlue => new Color(KnownColor.DarkSlateBlue);
94 
95         public static Color DarkSlateGray => new Color(KnownColor.DarkSlateGray);
96 
97         public static Color DarkTurquoise => new Color(KnownColor.DarkTurquoise);
98 
99         public static Color DarkViolet => new Color(KnownColor.DarkViolet);
100 
101         public static Color DeepPink => new Color(KnownColor.DeepPink);
102 
103         public static Color DeepSkyBlue => new Color(KnownColor.DeepSkyBlue);
104 
105         public static Color DimGray => new Color(KnownColor.DimGray);
106 
107         public static Color DodgerBlue => new Color(KnownColor.DodgerBlue);
108 
109         public static Color Firebrick => new Color(KnownColor.Firebrick);
110 
111         public static Color FloralWhite => new Color(KnownColor.FloralWhite);
112 
113         public static Color ForestGreen => new Color(KnownColor.ForestGreen);
114 
115         public static Color Fuchsia => new Color(KnownColor.Fuchsia);
116 
117         public static Color Gainsboro => new Color(KnownColor.Gainsboro);
118 
119         public static Color GhostWhite => new Color(KnownColor.GhostWhite);
120 
121         public static Color Gold => new Color(KnownColor.Gold);
122 
123         public static Color Goldenrod => new Color(KnownColor.Goldenrod);
124 
125         public static Color Gray => new Color(KnownColor.Gray);
126 
127         public static Color Green => new Color(KnownColor.Green);
128 
129         public static Color GreenYellow => new Color(KnownColor.GreenYellow);
130 
131         public static Color Honeydew => new Color(KnownColor.Honeydew);
132 
133         public static Color HotPink => new Color(KnownColor.HotPink);
134 
135         public static Color IndianRed => new Color(KnownColor.IndianRed);
136 
137         public static Color Indigo => new Color(KnownColor.Indigo);
138 
139         public static Color Ivory => new Color(KnownColor.Ivory);
140 
141         public static Color Khaki => new Color(KnownColor.Khaki);
142 
143         public static Color Lavender => new Color(KnownColor.Lavender);
144 
145         public static Color LavenderBlush => new Color(KnownColor.LavenderBlush);
146 
147         public static Color LawnGreen => new Color(KnownColor.LawnGreen);
148 
149         public static Color LemonChiffon => new Color(KnownColor.LemonChiffon);
150 
151         public static Color LightBlue => new Color(KnownColor.LightBlue);
152 
153         public static Color LightCoral => new Color(KnownColor.LightCoral);
154 
155         public static Color LightCyan => new Color(KnownColor.LightCyan);
156 
157         public static Color LightGoldenrodYellow => new Color(KnownColor.LightGoldenrodYellow);
158 
159         public static Color LightGreen => new Color(KnownColor.LightGreen);
160 
161         public static Color LightGray => new Color(KnownColor.LightGray);
162 
163         public static Color LightPink => new Color(KnownColor.LightPink);
164 
165         public static Color LightSalmon => new Color(KnownColor.LightSalmon);
166 
167         public static Color LightSeaGreen => new Color(KnownColor.LightSeaGreen);
168 
169         public static Color LightSkyBlue => new Color(KnownColor.LightSkyBlue);
170 
171         public static Color LightSlateGray => new Color(KnownColor.LightSlateGray);
172 
173         public static Color LightSteelBlue => new Color(KnownColor.LightSteelBlue);
174 
175         public static Color LightYellow => new Color(KnownColor.LightYellow);
176 
177         public static Color Lime => new Color(KnownColor.Lime);
178 
179         public static Color LimeGreen => new Color(KnownColor.LimeGreen);
180 
181         public static Color Linen => new Color(KnownColor.Linen);
182 
183         public static Color Magenta => new Color(KnownColor.Magenta);
184 
185         public static Color Maroon => new Color(KnownColor.Maroon);
186 
187         public static Color MediumAquamarine => new Color(KnownColor.MediumAquamarine);
188 
189         public static Color MediumBlue => new Color(KnownColor.MediumBlue);
190 
191         public static Color MediumOrchid => new Color(KnownColor.MediumOrchid);
192 
193         public static Color MediumPurple => new Color(KnownColor.MediumPurple);
194 
195         public static Color MediumSeaGreen => new Color(KnownColor.MediumSeaGreen);
196 
197         public static Color MediumSlateBlue => new Color(KnownColor.MediumSlateBlue);
198 
199         public static Color MediumSpringGreen => new Color(KnownColor.MediumSpringGreen);
200 
201         public static Color MediumTurquoise => new Color(KnownColor.MediumTurquoise);
202 
203         public static Color MediumVioletRed => new Color(KnownColor.MediumVioletRed);
204 
205         public static Color MidnightBlue => new Color(KnownColor.MidnightBlue);
206 
207         public static Color MintCream => new Color(KnownColor.MintCream);
208 
209         public static Color MistyRose => new Color(KnownColor.MistyRose);
210 
211         public static Color Moccasin => new Color(KnownColor.Moccasin);
212 
213         public static Color NavajoWhite => new Color(KnownColor.NavajoWhite);
214 
215         public static Color Navy => new Color(KnownColor.Navy);
216 
217         public static Color OldLace => new Color(KnownColor.OldLace);
218 
219         public static Color Olive => new Color(KnownColor.Olive);
220 
221         public static Color OliveDrab => new Color(KnownColor.OliveDrab);
222 
223         public static Color Orange => new Color(KnownColor.Orange);
224 
225         public static Color OrangeRed => new Color(KnownColor.OrangeRed);
226 
227         public static Color Orchid => new Color(KnownColor.Orchid);
228 
229         public static Color PaleGoldenrod => new Color(KnownColor.PaleGoldenrod);
230 
231         public static Color PaleGreen => new Color(KnownColor.PaleGreen);
232 
233         public static Color PaleTurquoise => new Color(KnownColor.PaleTurquoise);
234 
235         public static Color PaleVioletRed => new Color(KnownColor.PaleVioletRed);
236 
237         public static Color PapayaWhip => new Color(KnownColor.PapayaWhip);
238 
239         public static Color PeachPuff => new Color(KnownColor.PeachPuff);
240 
241         public static Color Peru => new Color(KnownColor.Peru);
242 
243         public static Color Pink => new Color(KnownColor.Pink);
244 
245         public static Color Plum => new Color(KnownColor.Plum);
246 
247         public static Color PowderBlue => new Color(KnownColor.PowderBlue);
248 
249         public static Color Purple => new Color(KnownColor.Purple);
250 
251         public static Color Red => new Color(KnownColor.Red);
252 
253         public static Color RosyBrown => new Color(KnownColor.RosyBrown);
254 
255         public static Color RoyalBlue => new Color(KnownColor.RoyalBlue);
256 
257         public static Color SaddleBrown => new Color(KnownColor.SaddleBrown);
258 
259         public static Color Salmon => new Color(KnownColor.Salmon);
260 
261         public static Color SandyBrown => new Color(KnownColor.SandyBrown);
262 
263         public static Color SeaGreen => new Color(KnownColor.SeaGreen);
264 
265         public static Color SeaShell => new Color(KnownColor.SeaShell);
266 
267         public static Color Sienna => new Color(KnownColor.Sienna);
268 
269         public static Color Silver => new Color(KnownColor.Silver);
270 
271         public static Color SkyBlue => new Color(KnownColor.SkyBlue);
272 
273         public static Color SlateBlue => new Color(KnownColor.SlateBlue);
274 
275         public static Color SlateGray => new Color(KnownColor.SlateGray);
276 
277         public static Color Snow => new Color(KnownColor.Snow);
278 
279         public static Color SpringGreen => new Color(KnownColor.SpringGreen);
280 
281         public static Color SteelBlue => new Color(KnownColor.SteelBlue);
282 
283         public static Color Tan => new Color(KnownColor.Tan);
284 
285         public static Color Teal => new Color(KnownColor.Teal);
286 
287         public static Color Thistle => new Color(KnownColor.Thistle);
288 
289         public static Color Tomato => new Color(KnownColor.Tomato);
290 
291         public static Color Turquoise => new Color(KnownColor.Turquoise);
292 
293         public static Color Violet => new Color(KnownColor.Violet);
294 
295         public static Color Wheat => new Color(KnownColor.Wheat);
296 
297         public static Color White => new Color(KnownColor.White);
298 
299         public static Color WhiteSmoke => new Color(KnownColor.WhiteSmoke);
300 
301         public static Color Yellow => new Color(KnownColor.Yellow);
302 
303         public static Color YellowGreen => new Color(KnownColor.YellowGreen);
304 
305         //
306         //  end "web" colors
307         // -------------------------------------------------------------------
308 
309         // NOTE : The "zero" pattern (all members being 0) must represent
310         //      : "not set". This allows "Color c;" to be correct.
311 
312         private const short StateKnownColorValid = 0x0001;
313         private const short StateARGBValueValid = 0x0002;
314         private const short StateValueMask = StateARGBValueValid;
315         private const short StateNameValid = 0x0008;
316         private const long NotDefinedValue = 0;
317 
318         /**
319          * Shift count and bit mask for A, R, G, B components in ARGB mode!
320          */
321         private const int ARGBAlphaShift = 24;
322         private const int ARGBRedShift = 16;
323         private const int ARGBGreenShift = 8;
324         private const int ARGBBlueShift = 0;
325 
326 
327         // user supplied name of color. Will not be filled in if
328         // we map to a "knowncolor"
329         //
330         private readonly string name; // Do not rename (binary serialization)
331 
332         // will contain standard 32bit sRGB (ARGB)
333         //
334         private readonly long value; // Do not rename (binary serialization)
335 
336         // ignored, unless "state" says it is valid
337         //
338         private readonly short knownColor; // Do not rename (binary serialization)
339 
340         // implementation specific information
341         //
342         private readonly short state; // Do not rename (binary serialization)
343 
344 
ColorSystem.Drawing.Color345         internal Color(KnownColor knownColor)
346         {
347             value = 0;
348             state = StateKnownColorValid;
349             name = null;
350             this.knownColor = unchecked((short)knownColor);
351         }
352 
ColorSystem.Drawing.Color353         private Color(long value, short state, string name, KnownColor knownColor)
354         {
355             this.value = value;
356             this.state = state;
357             this.name = name;
358             this.knownColor = unchecked((short)knownColor);
359         }
360 
361         public byte R => (byte)((Value >> ARGBRedShift) & 0xFF);
362 
363         public byte G => (byte)((Value >> ARGBGreenShift) & 0xFF);
364 
365         public byte B => (byte)((Value >> ARGBBlueShift) & 0xFF);
366 
367         public byte A => (byte)((Value >> ARGBAlphaShift) & 0xFF);
368 
369         public bool IsKnownColor => ((state & StateKnownColorValid) != 0);
370 
371         public bool IsEmpty => state == 0;
372 
373         public bool IsNamedColor => ((state & StateNameValid) != 0) || IsKnownColor;
374 
375         public bool IsSystemColor => IsKnownColor && ((((KnownColor) knownColor) <= KnownColor.WindowText) || (((KnownColor) knownColor) > KnownColor.YellowGreen));
376 
377         // Not localized because it's only used for the DebuggerDisplayAttribute, and the values are
378         // programmatic items.
379         // Also, don't inline into the attribute for performance reasons.  This way means the debugger
380         // does 1 func-eval instead of 5.
381         [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
382         private string NameAndARGBValue => $"{{Name={Name}, ARGB=({A}, {R}, {G}, {B})}}";
383 
384         public string Name
385         {
386             get
387             {
388                 if ((state & StateNameValid) != 0)
389                 {
390                     return name;
391                 }
392 
393                 if (IsKnownColor)
394                 {
395                     string tablename = KnownColorTable.KnownColorToName((KnownColor)knownColor);
396                     Debug.Assert(tablename != null, $"Could not find known color '{(KnownColor)knownColor}' in the KnownColorTable");
397 
398                     return tablename;
399                 }
400 
401                 // if we reached here, just encode the value
402                 //
403                 return Convert.ToString(value, 16);
404             }
405         }
406 
407         private long Value
408         {
409             get
410             {
411                 if ((state & StateValueMask) != 0)
412                 {
413                     return value;
414                 }
415 
416                 if (IsKnownColor)
417                 {
418                     return KnownColorTable.KnownColorToArgb((KnownColor)knownColor);
419                 }
420 
421                 return NotDefinedValue;
422             }
423         }
424 
CheckByteSystem.Drawing.Color425         private static void CheckByte(int value, string name)
426         {
427             if (value < 0 || value > 255)
428                 throw new ArgumentException(SR.Format(SR.InvalidEx2BoundArgument, name, value, 0, 255));
429         }
430 
MakeArgbSystem.Drawing.Color431         private static long MakeArgb(byte alpha, byte red, byte green, byte blue) =>
432             (long)unchecked((uint)(red << ARGBRedShift |
433                 green << ARGBGreenShift |
434                 blue << ARGBBlueShift |
435                 alpha << ARGBAlphaShift)) & 0xffffffff;
436 
FromArgbSystem.Drawing.Color437         public static Color FromArgb(int argb) => new Color(argb & 0xffffffff, StateARGBValueValid, null, 0);
438 
FromArgbSystem.Drawing.Color439         public static Color FromArgb(int alpha, int red, int green, int blue)
440         {
441             CheckByte(alpha, nameof(alpha));
442             CheckByte(red, nameof(red));
443             CheckByte(green, nameof(green));
444             CheckByte(blue, nameof(blue));
445             return new Color(MakeArgb((byte)alpha, (byte)red, (byte)green, (byte)blue), StateARGBValueValid, null, (KnownColor)0);
446         }
447 
FromArgbSystem.Drawing.Color448         public static Color FromArgb(int alpha, Color baseColor)
449         {
450             CheckByte(alpha, nameof(alpha));
451             // unchecked - because we already checked that alpha is a byte in CheckByte above
452             return new Color(MakeArgb(unchecked((byte)alpha), baseColor.R, baseColor.G, baseColor.B), StateARGBValueValid, null, (KnownColor)0);
453         }
454 
FromArgbSystem.Drawing.Color455         public static Color FromArgb(int red, int green, int blue) => FromArgb(255, red, green, blue);
456 
457         public static Color FromKnownColor(KnownColor color) =>
458             color <= 0 || color > KnownColor.MenuHighlight ? FromName(color.ToString()) : new Color(color);
459 
FromNameSystem.Drawing.Color460         public static Color FromName(string name)
461         {
462             // try to get a known color first
463             Color color;
464             if (ColorTable.TryGetNamedColor(name, out color))
465             {
466                 return color;
467             }
468             // otherwise treat it as a named color
469             return new Color(NotDefinedValue, StateNameValid, name, (KnownColor)0);
470         }
471 
GetBrightnessSystem.Drawing.Color472         public float GetBrightness()
473         {
474             float r = R / 255.0f;
475             float g = G / 255.0f;
476             float b = B / 255.0f;
477 
478             float max, min;
479 
480             max = r; min = r;
481 
482             if (g > max)
483             {
484                 max = g;
485             }
486             else if (g < min)
487             {
488                 min = g;
489             }
490 
491             if (b > max)
492             {
493                 max = b;
494             }
495             else if (b < min)
496             {
497                 min = b;
498             }
499 
500             return (max + min) / 2;
501         }
502 
503 
GetHueSystem.Drawing.Color504         public Single GetHue()
505         {
506             if (R == G && G == B)
507                 return 0; // 0 makes as good an UNDEFINED value as any
508 
509             float r = R / 255.0f;
510             float g = G / 255.0f;
511             float b = B / 255.0f;
512 
513             float max, min;
514             float delta;
515             float hue;
516 
517             max = r; min = r;
518 
519             if (g > max)
520             {
521                 max = g;
522             }
523             else if (g < min)
524             {
525                 min = g;
526             }
527 
528             if (b > max)
529             {
530                 max = b;
531             }
532             else if (b < min)
533             {
534                 min = b;
535             }
536 
537             delta = max - min;
538 
539             if (r == max)
540             {
541                 hue = (g - b) / delta;
542             }
543             else if (g == max)
544             {
545                 hue = 2 + (b - r) / delta;
546             }
547             else
548             {
549                 Debug.Assert(b == max);
550                 hue = 4 + (r - g) / delta;
551             }
552             hue *= 60;
553 
554             if (hue < 0.0f)
555             {
556                 hue += 360.0f;
557             }
558             return hue;
559         }
560 
GetSaturationSystem.Drawing.Color561         public float GetSaturation()
562         {
563             float r = R / 255.0f;
564             float g = G / 255.0f;
565             float b = B / 255.0f;
566 
567             float s = 0;
568 
569             float max = r;
570             float min = r;
571 
572             if (g > max)
573             {
574                 max = g;
575             }
576             else if (g < min)
577             {
578                 min = g;
579             }
580 
581             if (b > max)
582             {
583                 max = b;
584             }
585             else if (b < min)
586             {
587                 min = b;
588             }
589 
590             // if max == min, then there is no color and
591             // the saturation is zero.
592             //
593             if (max != min)
594             {
595                 float l = (max + min) / 2;
596 
597                 if (l <= .5)
598                 {
599                     s = (max - min) / (max + min);
600                 }
601                 else
602                 {
603                     s = (max - min) / (2 - max - min);
604                 }
605             }
606             return s;
607         }
608 
ToArgbSystem.Drawing.Color609         public int ToArgb() => unchecked((int)Value);
610 
ToKnownColorSystem.Drawing.Color611         public KnownColor ToKnownColor() => (KnownColor)knownColor;
612 
ToStringSystem.Drawing.Color613         public override string ToString()
614         {
615             if ((state & StateNameValid) != 0 || (state & StateKnownColorValid) != 0)
616             {
617                 return nameof(Color) + " [" + Name + "]";
618             }
619             else if ((state & StateValueMask) != 0)
620             {
621                 return nameof(Color) + " [A=" + A.ToString() + ", R=" + R.ToString() + ", G=" + G.ToString() + ", B=" + B.ToString() + "]";
622             }
623             else
624             {
625                 return nameof(Color) + " [Empty]";
626             }
627         }
628 
operator ==System.Drawing.Color629         public static bool operator ==(Color left, Color right) =>
630             left.value == right.value
631                 && left.state == right.state
632                 && left.knownColor == right.knownColor
633                 && left.name == right.name;
634 
operator !=System.Drawing.Color635         public static bool operator !=(Color left, Color right) => !(left == right);
636 
637         public override bool Equals(object obj) => obj is Color && Equals((Color)obj);
638 
639         public bool Equals(Color other) => this == other;
640 
GetHashCodeSystem.Drawing.Color641         public override int GetHashCode()
642         {
643             // Three cases:
644             // 1. We don't have a name. All relevant data, including this fact, is in the remaining fields.
645             // 2. We have a known name. The name will be the same instance of any other with the same
646             // knownColor value, so we can ignore it for hashing. Note this also hashes different to
647             // an unnamed color with the same ARGB value.
648             // 3. Have an unknown name. Will differ from other unknown-named colors only by name, so we
649             // can usefully use the names hash code alone.
650             if (name != null & !IsKnownColor)
651                 return name.GetHashCode();
652 
653             return HashHelpers.Combine(
654                 HashHelpers.Combine(value.GetHashCode(), state.GetHashCode()), knownColor.GetHashCode());
655         }
656     }
657 }
658