using System; using System.Linq; using System.Globalization; namespace Xamarin.Forms { [Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.ColorTypeConverter")] public class ColorTypeConverter : TypeConverter { // Supported inputs // HEX #rgb, #argb, #rrggbb, #aarrggbb // RGB rgb(255,0,0), rgb(100%,0%,0%) values in range 0-255 or 0%-100% // RGBA rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8) opacity is 0.0-1.0 // HSL hsl(120, 100%, 50%) h is 0-360, s and l are 0%-100% // HSLA hsla(120, 100%, 50%, .8) opacity is 0.0-1.0 // Predefined color case insensitive public override object ConvertFromInvariantString(string value) { if (value != null) { value = value.Trim(); if (value.StartsWith("#", StringComparison.Ordinal)) return Color.FromHex(value); if (value.StartsWith("rgba", StringComparison.OrdinalIgnoreCase)) { var op = value.IndexOf('('); var cp = value.LastIndexOf(')'); if (op < 0 || cp < 0 || cp < op) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var quad = value.Substring(op + 1, cp - op - 1).Split(','); if (quad.Length != 4) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var r = ParseColorValue(quad[0], 255, acceptPercent: true); var g = ParseColorValue(quad[1], 255, acceptPercent: true); var b = ParseColorValue(quad[2], 255, acceptPercent: true); var a = ParseOpacity(quad[3]); return new Color(r, g, b, a); } if (value.StartsWith("rgb", StringComparison.OrdinalIgnoreCase)) { var op = value.IndexOf('('); var cp = value.LastIndexOf(')'); if (op < 0 || cp < 0 || cp < op) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var triplet = value.Substring(op + 1, cp - op - 1).Split(','); if (triplet.Length != 3) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var r = ParseColorValue(triplet[0], 255, acceptPercent: true); var g = ParseColorValue(triplet[1], 255, acceptPercent: true); var b = ParseColorValue(triplet[2], 255, acceptPercent: true); return new Color(r, g, b); } if (value.StartsWith("hsla", StringComparison.OrdinalIgnoreCase)) { var op = value.IndexOf('('); var cp = value.LastIndexOf(')'); if (op < 0 || cp < 0 || cp < op) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var quad = value.Substring(op + 1, cp - op - 1).Split(','); if (quad.Length != 4) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var h = ParseColorValue(quad[0], 360, acceptPercent: false); var s = ParseColorValue(quad[1], 100, acceptPercent: true); var l = ParseColorValue(quad[2], 100, acceptPercent: true); var a = ParseOpacity(quad[3]); return Color.FromHsla(h, s, l, a); } if (value.StartsWith("hsl", StringComparison.OrdinalIgnoreCase)) { var op = value.IndexOf('('); var cp = value.LastIndexOf(')'); if (op < 0 || cp < 0 || cp < op) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var triplet = value.Substring(op + 1, cp - op - 1).Split(','); if (triplet.Length != 3) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); var h = ParseColorValue(triplet[0], 360, acceptPercent: false); var s = ParseColorValue(triplet[1], 100, acceptPercent: true); var l = ParseColorValue(triplet[2], 100, acceptPercent: true); return Color.FromHsla(h, s, l); } string[] parts = value.Split('.'); if (parts.Length == 1 || (parts.Length == 2 && parts[0] == "Color")) { string color = parts[parts.Length - 1]; switch (color.ToLowerInvariant()) { case "default": return Color.Default; case "accent": return Color.Accent; case "aliceblue": return Color.AliceBlue; case "antiquewhite": return Color.AntiqueWhite; case "aqua": return Color.Aqua; case "aquamarine": return Color.Aquamarine; case "azure": return Color.Azure; case "beige": return Color.Beige; case "bisque": return Color.Bisque; case "black": return Color.Black; case "blanchedalmond": return Color.BlanchedAlmond; case "blue": return Color.Blue; case "blueViolet": return Color.BlueViolet; case "brown": return Color.Brown; case "burlywood": return Color.BurlyWood; case "cadetblue": return Color.CadetBlue; case "chartreuse": return Color.Chartreuse; case "chocolate": return Color.Chocolate; case "coral": return Color.Coral; case "cornflowerblue": return Color.CornflowerBlue; case "cornsilk": return Color.Cornsilk; case "crimson": return Color.Crimson; case "cyan": return Color.Cyan; case "darkblue": return Color.DarkBlue; case "darkcyan": return Color.DarkCyan; case "darkgoldenrod": return Color.DarkGoldenrod; case "darkgray": return Color.DarkGray; case "darkgreen": return Color.DarkGreen; case "darkkhaki": return Color.DarkKhaki; case "darkmagenta": return Color.DarkMagenta; case "darkolivegreen": return Color.DarkOliveGreen; case "darkorange": return Color.DarkOrange; case "darkorchid": return Color.DarkOrchid; case "darkred": return Color.DarkRed; case "darksalmon": return Color.DarkSalmon; case "darkseagreen": return Color.DarkSeaGreen; case "darkslateblue": return Color.DarkSlateBlue; case "darkslategray": return Color.DarkSlateGray; case "darkturquoise": return Color.DarkTurquoise; case "darkviolet": return Color.DarkViolet; case "deeppink": return Color.DeepPink; case "deepskyblue": return Color.DeepSkyBlue; case "dimgray": return Color.DimGray; case "dodgerblue": return Color.DodgerBlue; case "firebrick": return Color.Firebrick; case "floralwhite": return Color.FloralWhite; case "forestgreen": return Color.ForestGreen; case "fuchsia": return Color.Fuchsia; case "gainsboro": return Color.Gainsboro; case "ghostwhite": return Color.GhostWhite; case "gold": return Color.Gold; case "goldenrod": return Color.Goldenrod; case "gray": return Color.Gray; case "green": return Color.Green; case "greenyellow": return Color.GreenYellow; case "honeydew": return Color.Honeydew; case "hotpink": return Color.HotPink; case "indianred": return Color.IndianRed; case "indigo": return Color.Indigo; case "ivory": return Color.Ivory; case "khaki": return Color.Khaki; case "lavender": return Color.Lavender; case "lavenderblush": return Color.LavenderBlush; case "lawngreen": return Color.LawnGreen; case "lemonchiffon": return Color.LemonChiffon; case "lightblue": return Color.LightBlue; case "lightcoral": return Color.LightCoral; case "lightcyan": return Color.LightCyan; case "lightgoldenrodyellow": return Color.LightGoldenrodYellow; case "lightgray": return Color.LightGray; case "lightgreen": return Color.LightGreen; case "lightpink": return Color.LightPink; case "lightsalmon": return Color.LightSalmon; case "lightseagreen": return Color.LightSeaGreen; case "lightskyblue": return Color.LightSkyBlue; case "lightslategray": return Color.LightSlateGray; case "lightsteelblue": return Color.LightSteelBlue; case "lightyellow": return Color.LightYellow; case "lime": return Color.Lime; case "limegreen": return Color.LimeGreen; case "linen": return Color.Linen; case "magenta": return Color.Magenta; case "maroon": return Color.Maroon; case "mediumaquamarine": return Color.MediumAquamarine; case "mediumblue": return Color.MediumBlue; case "mediumorchid": return Color.MediumOrchid; case "mediumpurple": return Color.MediumPurple; case "mediumseagreen": return Color.MediumSeaGreen; case "mediumslateblue": return Color.MediumSlateBlue; case "mediumspringgreen": return Color.MediumSpringGreen; case "mediumturquoise": return Color.MediumTurquoise; case "mediumvioletred": return Color.MediumVioletRed; case "midnightblue": return Color.MidnightBlue; case "mintcream": return Color.MintCream; case "mistyrose": return Color.MistyRose; case "moccasin": return Color.Moccasin; case "navajowhite": return Color.NavajoWhite; case "navy": return Color.Navy; case "oldlace": return Color.OldLace; case "olive": return Color.Olive; case "olivedrab": return Color.OliveDrab; case "orange": return Color.Orange; case "orangered": return Color.OrangeRed; case "orchid": return Color.Orchid; case "palegoldenrod": return Color.PaleGoldenrod; case "palegreen": return Color.PaleGreen; case "paleturquoise": return Color.PaleTurquoise; case "palevioletred": return Color.PaleVioletRed; case "papayawhip": return Color.PapayaWhip; case "peachpuff": return Color.PeachPuff; case "peru": return Color.Peru; case "pink": return Color.Pink; case "plum": return Color.Plum; case "powderblue": return Color.PowderBlue; case "purple": return Color.Purple; case "red": return Color.Red; case "rosybrown": return Color.RosyBrown; case "royalblue": return Color.RoyalBlue; case "saddlebrown": return Color.SaddleBrown; case "salmon": return Color.Salmon; case "sandybrown": return Color.SandyBrown; case "seagreen": return Color.SeaGreen; case "seashell": return Color.SeaShell; case "sienna": return Color.Sienna; case "silver": return Color.Silver; case "skyblue": return Color.SkyBlue; case "slateblue": return Color.SlateBlue; case "slategray": return Color.SlateGray; case "snow": return Color.Snow; case "springgreen": return Color.SpringGreen; case "steelblue": return Color.SteelBlue; case "tan": return Color.Tan; case "teal": return Color.Teal; case "thistle": return Color.Thistle; case "tomato": return Color.Tomato; case "transparent": return Color.Transparent; case "turquoise": return Color.Turquoise; case "violet": return Color.Violet; case "wheat": return Color.Wheat; case "white": return Color.White; case "whitesmoke": return Color.WhiteSmoke; case "yellow": return Color.Yellow; case "yellowgreen": return Color.YellowGreen; } var field = typeof(Color).GetFields().FirstOrDefault(fi => fi.IsStatic && string.Equals(fi.Name, color, StringComparison.OrdinalIgnoreCase)); if (field != null) return (Color)field.GetValue(null); var property = typeof(Color).GetProperties().FirstOrDefault(pi => string.Equals(pi.Name, color, StringComparison.OrdinalIgnoreCase) && pi.CanRead && pi.GetMethod.IsStatic); if (property != null) return (Color)property.GetValue(null, null); } } throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}"); } static double ParseColorValue(string elem, int maxValue, bool acceptPercent) { elem = elem.Trim(); if (elem.EndsWith("%", StringComparison.Ordinal) && acceptPercent) { maxValue = 100; elem = elem.Substring(0, elem.Length - 1); } return (double)(int.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, maxValue)) / maxValue; } static double ParseOpacity(string elem) { return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, 1); } } }