3 using System.Globalization;
4 using Xamarin.Forms.Internals;
6 namespace Xamarin.Forms
8 [Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.ColorTypeConverter")]
9 [Xaml.TypeConversion(typeof(Color))]
10 public class ColorTypeConverter : TypeConverter
13 // HEX #rgb, #argb, #rrggbb, #aarrggbb
14 // RGB rgb(255,0,0), rgb(100%,0%,0%) values in range 0-255 or 0%-100%
15 // RGBA rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8) opacity is 0.0-1.0
16 // HSL hsl(120, 100%, 50%) h is 0-360, s and l are 0%-100%
17 // HSLA hsla(120, 100%, 50%, .8) opacity is 0.0-1.0
18 // HSV hsv(120, 100%, 50%) h is 0-360, s and v are 0%-100%
19 // HSVA hsva(120, 100%, 50%, .8) opacity is 0.0-1.0
20 // Predefined color case insensitive
21 public override object ConvertFromInvariantString(string value)
26 if (value.StartsWith("#", StringComparison.Ordinal))
27 return Color.FromHex(value);
29 if (value.StartsWith("rgba", StringComparison.OrdinalIgnoreCase)) {
30 var op = value.IndexOf('(');
31 var cp = value.LastIndexOf(')');
32 if (op < 0 || cp < 0 || cp < op)
33 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
34 var quad = value.Substring(op + 1, cp - op - 1).Split(',');
36 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
37 var r = ParseColorValue(quad[0], 255, acceptPercent: true);
38 var g = ParseColorValue(quad[1], 255, acceptPercent: true);
39 var b = ParseColorValue(quad[2], 255, acceptPercent: true);
40 var a = ParseOpacity(quad[3]);
41 return new Color(r, g, b, a);
44 if (value.StartsWith("rgb", StringComparison.OrdinalIgnoreCase)) {
45 var op = value.IndexOf('(');
46 var cp = value.LastIndexOf(')');
47 if (op < 0 || cp < 0 || cp < op)
48 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
49 var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
50 if (triplet.Length != 3)
51 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
52 var r = ParseColorValue(triplet[0], 255, acceptPercent: true);
53 var g = ParseColorValue(triplet[1], 255, acceptPercent: true);
54 var b = ParseColorValue(triplet[2], 255, acceptPercent: true);
55 return new Color(r, g, b);
58 if (value.StartsWith("hsla", StringComparison.OrdinalIgnoreCase)) {
59 var op = value.IndexOf('(');
60 var cp = value.LastIndexOf(')');
61 if (op < 0 || cp < 0 || cp < op)
62 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
63 var quad = value.Substring(op + 1, cp - op - 1).Split(',');
65 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
66 var h = ParseColorValue(quad[0], 360, acceptPercent: false);
67 var s = ParseColorValue(quad[1], 100, acceptPercent: true);
68 var l = ParseColorValue(quad[2], 100, acceptPercent: true);
69 var a = ParseOpacity(quad[3]);
70 return Color.FromHsla(h, s, l, a);
73 if (value.StartsWith("hsl", StringComparison.OrdinalIgnoreCase)) {
74 var op = value.IndexOf('(');
75 var cp = value.LastIndexOf(')');
76 if (op < 0 || cp < 0 || cp < op)
77 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
78 var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
79 if (triplet.Length != 3)
80 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
81 var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
82 var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
83 var l = ParseColorValue(triplet[2], 100, acceptPercent: true);
84 return Color.FromHsla(h, s, l);
87 if (value.StartsWith("hsva", StringComparison.OrdinalIgnoreCase))
89 var op = value.IndexOf('(');
90 var cp = value.LastIndexOf(')');
91 if (op < 0 || cp < 0 || cp < op)
92 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
93 var quad = value.Substring(op + 1, cp - op - 1).Split(',');
95 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
96 var h = ParseColorValue(quad[0], 360, acceptPercent: false);
97 var s = ParseColorValue(quad[1], 100, acceptPercent: true);
98 var v = ParseColorValue(quad[2], 100, acceptPercent: true);
99 var a = ParseOpacity(quad[3]);
100 return Color.FromHsva(h, s, v, a);
103 if (value.StartsWith("hsv", StringComparison.OrdinalIgnoreCase))
105 var op = value.IndexOf('(');
106 var cp = value.LastIndexOf(')');
107 if (op < 0 || cp < 0 || cp < op)
108 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
109 var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
110 if (triplet.Length != 3)
111 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
112 var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
113 var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
114 var v = ParseColorValue(triplet[2], 100, acceptPercent: true);
115 return Color.FromHsv(h, s, v);
118 string[] parts = value.Split('.');
119 if (parts.Length == 1 || (parts.Length == 2 && parts[0] == "Color"))
121 string color = parts[parts.Length - 1];
122 switch (color.ToLowerInvariant()) {
123 case "default": return Color.Default;
124 case "accent": return Color.Accent;
125 case "aliceblue": return Color.AliceBlue;
126 case "antiquewhite": return Color.AntiqueWhite;
127 case "aqua": return Color.Aqua;
128 case "aquamarine": return Color.Aquamarine;
129 case "azure": return Color.Azure;
130 case "beige": return Color.Beige;
131 case "bisque": return Color.Bisque;
132 case "black": return Color.Black;
133 case "blanchedalmond": return Color.BlanchedAlmond;
134 case "blue": return Color.Blue;
135 case "blueViolet": return Color.BlueViolet;
136 case "brown": return Color.Brown;
137 case "burlywood": return Color.BurlyWood;
138 case "cadetblue": return Color.CadetBlue;
139 case "chartreuse": return Color.Chartreuse;
140 case "chocolate": return Color.Chocolate;
141 case "coral": return Color.Coral;
142 case "cornflowerblue": return Color.CornflowerBlue;
143 case "cornsilk": return Color.Cornsilk;
144 case "crimson": return Color.Crimson;
145 case "cyan": return Color.Cyan;
146 case "darkblue": return Color.DarkBlue;
147 case "darkcyan": return Color.DarkCyan;
148 case "darkgoldenrod": return Color.DarkGoldenrod;
149 case "darkgray": return Color.DarkGray;
150 case "darkgreen": return Color.DarkGreen;
151 case "darkkhaki": return Color.DarkKhaki;
152 case "darkmagenta": return Color.DarkMagenta;
153 case "darkolivegreen": return Color.DarkOliveGreen;
154 case "darkorange": return Color.DarkOrange;
155 case "darkorchid": return Color.DarkOrchid;
156 case "darkred": return Color.DarkRed;
157 case "darksalmon": return Color.DarkSalmon;
158 case "darkseagreen": return Color.DarkSeaGreen;
159 case "darkslateblue": return Color.DarkSlateBlue;
160 case "darkslategray": return Color.DarkSlateGray;
161 case "darkturquoise": return Color.DarkTurquoise;
162 case "darkviolet": return Color.DarkViolet;
163 case "deeppink": return Color.DeepPink;
164 case "deepskyblue": return Color.DeepSkyBlue;
165 case "dimgray": return Color.DimGray;
166 case "dodgerblue": return Color.DodgerBlue;
167 case "firebrick": return Color.Firebrick;
168 case "floralwhite": return Color.FloralWhite;
169 case "forestgreen": return Color.ForestGreen;
170 case "fuchsia": return Color.Fuchsia;
171 case "gainsboro": return Color.Gainsboro;
172 case "ghostwhite": return Color.GhostWhite;
173 case "gold": return Color.Gold;
174 case "goldenrod": return Color.Goldenrod;
175 case "gray": return Color.Gray;
176 case "green": return Color.Green;
177 case "greenyellow": return Color.GreenYellow;
178 case "honeydew": return Color.Honeydew;
179 case "hotpink": return Color.HotPink;
180 case "indianred": return Color.IndianRed;
181 case "indigo": return Color.Indigo;
182 case "ivory": return Color.Ivory;
183 case "khaki": return Color.Khaki;
184 case "lavender": return Color.Lavender;
185 case "lavenderblush": return Color.LavenderBlush;
186 case "lawngreen": return Color.LawnGreen;
187 case "lemonchiffon": return Color.LemonChiffon;
188 case "lightblue": return Color.LightBlue;
189 case "lightcoral": return Color.LightCoral;
190 case "lightcyan": return Color.LightCyan;
191 case "lightgoldenrodyellow": return Color.LightGoldenrodYellow;
193 case "lightgray": return Color.LightGray;
194 case "lightgreen": return Color.LightGreen;
195 case "lightpink": return Color.LightPink;
196 case "lightsalmon": return Color.LightSalmon;
197 case "lightseagreen": return Color.LightSeaGreen;
198 case "lightskyblue": return Color.LightSkyBlue;
199 case "lightslategray": return Color.LightSlateGray;
200 case "lightsteelblue": return Color.LightSteelBlue;
201 case "lightyellow": return Color.LightYellow;
202 case "lime": return Color.Lime;
203 case "limegreen": return Color.LimeGreen;
204 case "linen": return Color.Linen;
205 case "magenta": return Color.Magenta;
206 case "maroon": return Color.Maroon;
207 case "mediumaquamarine": return Color.MediumAquamarine;
208 case "mediumblue": return Color.MediumBlue;
209 case "mediumorchid": return Color.MediumOrchid;
210 case "mediumpurple": return Color.MediumPurple;
211 case "mediumseagreen": return Color.MediumSeaGreen;
212 case "mediumslateblue": return Color.MediumSlateBlue;
213 case "mediumspringgreen": return Color.MediumSpringGreen;
214 case "mediumturquoise": return Color.MediumTurquoise;
215 case "mediumvioletred": return Color.MediumVioletRed;
216 case "midnightblue": return Color.MidnightBlue;
217 case "mintcream": return Color.MintCream;
218 case "mistyrose": return Color.MistyRose;
219 case "moccasin": return Color.Moccasin;
220 case "navajowhite": return Color.NavajoWhite;
221 case "navy": return Color.Navy;
222 case "oldlace": return Color.OldLace;
223 case "olive": return Color.Olive;
224 case "olivedrab": return Color.OliveDrab;
225 case "orange": return Color.Orange;
226 case "orangered": return Color.OrangeRed;
227 case "orchid": return Color.Orchid;
228 case "palegoldenrod": return Color.PaleGoldenrod;
229 case "palegreen": return Color.PaleGreen;
230 case "paleturquoise": return Color.PaleTurquoise;
231 case "palevioletred": return Color.PaleVioletRed;
232 case "papayawhip": return Color.PapayaWhip;
233 case "peachpuff": return Color.PeachPuff;
234 case "peru": return Color.Peru;
235 case "pink": return Color.Pink;
236 case "plum": return Color.Plum;
237 case "powderblue": return Color.PowderBlue;
238 case "purple": return Color.Purple;
239 case "red": return Color.Red;
240 case "rosybrown": return Color.RosyBrown;
241 case "royalblue": return Color.RoyalBlue;
242 case "saddlebrown": return Color.SaddleBrown;
243 case "salmon": return Color.Salmon;
244 case "sandybrown": return Color.SandyBrown;
245 case "seagreen": return Color.SeaGreen;
246 case "seashell": return Color.SeaShell;
247 case "sienna": return Color.Sienna;
248 case "silver": return Color.Silver;
249 case "skyblue": return Color.SkyBlue;
250 case "slateblue": return Color.SlateBlue;
251 case "slategray": return Color.SlateGray;
252 case "snow": return Color.Snow;
253 case "springgreen": return Color.SpringGreen;
254 case "steelblue": return Color.SteelBlue;
255 case "tan": return Color.Tan;
256 case "teal": return Color.Teal;
257 case "thistle": return Color.Thistle;
258 case "tomato": return Color.Tomato;
259 case "transparent": return Color.Transparent;
260 case "turquoise": return Color.Turquoise;
261 case "violet": return Color.Violet;
262 case "wheat": return Color.Wheat;
263 case "white": return Color.White;
264 case "whitesmoke": return Color.WhiteSmoke;
265 case "yellow": return Color.Yellow;
266 case "yellowgreen": return Color.YellowGreen;
268 var field = typeof(Color).GetFields().FirstOrDefault(fi => fi.IsStatic && string.Equals(fi.Name, color, StringComparison.OrdinalIgnoreCase));
270 return (Color)field.GetValue(null);
271 var property = typeof(Color).GetProperties().FirstOrDefault(pi => string.Equals(pi.Name, color, StringComparison.OrdinalIgnoreCase) && pi.CanRead && pi.GetMethod.IsStatic);
272 if (property != null)
273 return (Color)property.GetValue(null, null);
277 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
280 static double ParseColorValue(string elem, int maxValue, bool acceptPercent)
283 if (elem.EndsWith("%", StringComparison.Ordinal) && acceptPercent) {
285 elem = elem.Substring(0, elem.Length - 1);
287 return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, maxValue) / maxValue;
290 static double ParseOpacity(string elem)
292 return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, 1);