package color import ( "fmt" "math" "regexp" "strconv" "strings" "github.com/lucasb-eyer/go-colorful" "github.com/mazznoer/csscolorparser" ) var themeColorRegex = regexp.MustCompile(`^(N[1-7]|B[1-6]|AA[245]|AB[45])$`) func IsThemeColor(colorString string) bool { return themeColorRegex.MatchString(colorString) } func Darken(colorString string) (string, error) { if IsThemeColor(colorString) { switch { case colorString[0] == 'B': switch colorString[1] { case '1', '2': return B1, nil case '3': return B2, nil case '4': return B3, nil case '5': return B4, nil case '6': return B5, nil } case colorString[0:2] == "AA": switch colorString[2] { case '2', '4': return AA2, nil case '5': return AA4, nil } case colorString[0:2] == "AB": switch colorString[2] { case '4': return AB4, nil case '5': return AB5, nil } case colorString[0] == 'N': switch colorString[1] { case '1', '2': return N1, nil case '3': return N2, nil case '4': return N3, nil case '5': return N4, nil case '6': return N5, nil case '7': return N6, nil } } return "", fmt.Errorf("invalid color \"%s\"", colorString) } return darkenCSS(colorString) } func darkenCSS(colorString string) (string, error) { c, err := csscolorparser.Parse(colorString) if err != nil { return "", err } h, s, l := colorful.Color{R: c.R, G: c.G, B: c.B}.Hsl() // decrease luminance by 10% return colorful.Hsl(h, s, l-.1).Clamped().Hex(), nil } func LuminanceCategory(colorString string) (string, error) { l, err := Luminance(colorString) if err != nil { return "", err } switch { case l >= .88: return "bright", nil case l >= .55: return "normal", nil case l >= .30: return "dark", nil default: return "darker", nil } } func Luminance(colorString string) (float64, error) { c, err := csscolorparser.Parse(colorString) if err != nil { return 0, err } // https://stackoverflow.com/a/596243 l := float64( float64(0.299)*float64(c.R) + float64(0.587)*float64(c.G) + float64(0.114)*float64(c.B), ) return l, nil } const ( N1 = "N1" // foreground color N2 = "N2" N3 = "N3" N4 = "N4" N5 = "N5" N6 = "N6" N7 = "N7" // background color // Base Colors: used for containers B1 = "B1" B2 = "B2" B3 = "B3" B4 = "B4" B5 = "B5" B6 = "B6" // Alternative colors A AA2 = "AA2" AA4 = "AA4" AA5 = "AA5" // Alternative colors B AB4 = "AB4" AB5 = "AB5" // Special Empty = "" None = "none" ) type RGB struct { Red uint8 Green uint8 Blue uint8 } // https://github.com/go-playground/colors/blob/main/rgb.go#L89 func (c *RGB) IsLight() bool { r := float64(c.Red) g := float64(c.Green) b := float64(c.Blue) hsp := math.Sqrt(0.299*math.Pow(r, 2) + 0.587*math.Pow(g, 2) + 0.114*math.Pow(b, 2)) return hsp > 130 } // https://gist.github.com/CraigChilds94/6514edbc6a2db5e434a245487c525c75 func Hex2RGB(hex string) (RGB, error) { var rgb RGB if len(hex) > 3 && hex[0] == '#' { hex = hex[1:] } else { return RGB{}, fmt.Errorf("cannot parse hex color %v", hex) } values, err := strconv.ParseUint(hex, 16, 32) if err != nil { return RGB{}, err } rgb = RGB{ Red: uint8(values >> 16), Green: uint8((values >> 8) & 0xFF), Blue: uint8(values & 0xFF), } return rgb, nil } // https://www.w3.org/TR/css-color-4/#svg-color var namedRgbMap = map[string][]uint8{ "aliceblue": {240, 248, 255}, // #F0F8FF "antiquewhite": {250, 235, 215}, // #FAEBD7 "aqua": {0, 255, 255}, // #00FFFF "aquamarine": {127, 255, 212}, // #7FFFD4 "azure": {240, 255, 255}, // #F0FFFF "beige": {245, 245, 220}, // #F5F5DC "bisque": {255, 228, 196}, // #FFE4C4 "black": {0, 0, 0}, // #000000 "blanchedalmond": {255, 235, 205}, // #FFEBCD "blue": {0, 0, 255}, // #0000FF "blueviolet": {138, 43, 226}, // #8A2BE2 "brown": {165, 42, 42}, // #A52A2A "burlywood": {222, 184, 135}, // #DEB887 "cadetblue": {95, 158, 160}, // #5F9EA0 "chartreuse": {127, 255, 0}, // #7FFF00 "chocolate": {210, 105, 30}, // #D2691E "coral": {255, 127, 80}, // #FF7F50 "cornflowerblue": {100, 149, 237}, // #6495ED "cornsilk": {255, 248, 220}, // #FFF8DC "crimson": {220, 20, 60}, // #DC143C "cyan": {0, 255, 255}, // #00FFFF "darkblue": {0, 0, 139}, // #00008B "darkcyan": {0, 139, 139}, // #008B8B "darkgoldenrod": {184, 134, 11}, // #B8860B "darkgray": {169, 169, 169}, // #A9A9A9 "darkgreen": {0, 100, 0}, // #006400 "darkgrey": {169, 169, 169}, // #A9A9A9 "darkkhaki": {189, 183, 107}, // #BDB76B "darkmagenta": {139, 0, 139}, // #8B008B "darkolivegreen": {85, 107, 47}, // #556B2F "darkorange": {255, 140, 0}, // #FF8C00 "darkorchid": {153, 50, 204}, // #9932CC "darkred": {139, 0, 0}, // #8B0000 "darksalmon": {233, 150, 122}, // #E9967A "darkseagreen": {143, 188, 143}, // #8FBC8F "darkslateblue": {72, 61, 139}, // #483D8B "darkslategray": {47, 79, 79}, // #2F4F4F "darkslategrey": {47, 79, 79}, // #2F4F4F "darkturquoise": {0, 206, 209}, // #00CED1 "darkviolet": {148, 0, 211}, // #9400D3 "deeppink": {255, 20, 147}, // #FF1493 "deepskyblue": {0, 191, 255}, // #00BFFF "dimgray": {105, 105, 105}, // #696969 "dimgrey": {105, 105, 105}, // #696969 "dodgerblue": {30, 144, 255}, // #1E90FF "firebrick": {178, 34, 34}, // #B22222 "floralwhite": {255, 250, 240}, // #FFFAF0 "forestgreen": {34, 139, 34}, // #228B22 "fuchsia": {255, 0, 255}, // #FF00FF "gainsboro": {220, 220, 220}, // #DCDCDC "ghostwhite": {248, 248, 255}, // #F8F8FF "gold": {255, 215, 0}, // #FFD700 "goldenrod": {218, 165, 32}, // #DAA520 "gray": {128, 128, 128}, // #808080 "green": {0, 128, 0}, // #008000 "greenyellow": {173, 255, 47}, // #ADFF2F "grey": {128, 128, 128}, // #808080 "honeydew": {240, 255, 240}, // #F0FFF0 "hotpink": {255, 105, 180}, // #FF69B4 "indianred": {205, 92, 92}, // #CD5C5C "indigo": {75, 0, 130}, // #4B0082 "ivory": {255, 255, 240}, // #FFFFF0 "khaki": {240, 230, 140}, // #F0E68C "lavender": {230, 230, 250}, // #E6E6FA "lavenderblush": {255, 240, 245}, // #FFF0F5 "lawngreen": {124, 252, 0}, // #7CFC00 "lemonchiffon": {255, 250, 205}, // #FFFACD "lightblue": {173, 216, 230}, // #ADD8E6 "lightcoral": {240, 128, 128}, // #F08080 "lightcyan": {224, 255, 255}, // #E0FFFF "lightgoldenrodyellow": {250, 250, 210}, // #FAFAD2 "lightgray": {211, 211, 211}, // #D3D3D3 "lightgreen": {144, 238, 144}, // #90EE90 "lightgrey": {211, 211, 211}, // #D3D3D3 "lightpink": {255, 182, 193}, // #FFB6C1 "lightsalmon": {255, 160, 122}, // #FFA07A "lightseagreen": {32, 178, 170}, // #20B2AA "lightskyblue": {135, 206, 250}, // #87CEFA "lightslategray": {119, 136, 153}, // #778899 "lightslategrey": {119, 136, 153}, // #778899 "lightsteelblue": {176, 196, 222}, // #B0C4DE "lightyellow": {255, 255, 224}, // #FFFFE0 "lime": {0, 255, 0}, // #00FF00 "limegreen": {50, 205, 50}, // #32CD32 "linen": {250, 240, 230}, // #FAF0E6 "magenta": {255, 0, 255}, // #FF00FF "maroon": {128, 0, 0}, // #800000 "mediumaquamarine": {102, 205, 170}, // #66CDAA "mediumblue": {0, 0, 205}, // #0000CD "mediumorchid": {186, 85, 211}, // #BA55D3 "mediumpurple": {147, 112, 219}, // #9370DB "mediumseagreen": {60, 179, 113}, // #3CB371 "mediumslateblue": {123, 104, 238}, // #7B68EE "mediumspringgreen": {0, 250, 154}, // #00FA9A "mediumturquoise": {72, 209, 204}, // #48D1CC "mediumvioletred": {199, 21, 133}, // #C71585 "midnightblue": {25, 25, 112}, // #191970 "muintcream": {245, 255, 250}, // #F5FFFA "mistyrose": {255, 228, 225}, // #FFE4E1 "moccasin": {255, 228, 181}, // #FFE4B5 "navajowhite": {255, 222, 173}, // #FFDEAD "navy": {0, 0, 128}, // #000080 "oldlace": {253, 245, 230}, // #FDF5E6 "olive": {128, 128, 0}, // #808000 "olivedrab": {107, 142, 35}, // #6B8E23 "orange": {255, 165, 0}, // #FFA500 "orangered": {255, 69, 0}, // #FF4500 "orchid": {218, 112, 214}, // #DA70D6 "palegoldenrod": {238, 232, 170}, // #EEE8AA "palegreen": {152, 251, 152}, // #98FB98 "paleturquoise": {175, 238, 238}, // #AFEEEE "palevioletred": {219, 112, 147}, // #DB7093 "papayawhip": {255, 239, 213}, // #FFEFD5 "peachpuff": {255, 218, 185}, // #FFDAB9 "peru": {205, 133, 63}, // #CD853F "pink": {255, 192, 203}, // #FFC0CB "plum": {221, 160, 221}, // #DDA0DD "powderblue": {176, 224, 230}, // #B0E0E6 "purple": {128, 0, 128}, // #800080 "red": {255, 0, 0}, // #FF0000 "rebeccapurple": {102, 51, 153}, // #663399 "rosybrown": {188, 143, 143}, // #BC8F8F "royalblue": {65, 105, 225}, // #4169E1 "saddlebrown": {139, 69, 19}, // #8B4513 "salmon": {250, 128, 114}, // #FA8072 "sandybrown": {244, 164, 96}, // #F4A460 "seagreen": {46, 139, 87}, // #2E8B57 "seashell": {255, 245, 238}, // #FFF5EE "sienna": {160, 82, 45}, // #A0522D "silver": {192, 192, 192}, // #C0C0C0 "skyblue": {135, 206, 235}, // #87CEEB "slateblue": {106, 90, 205}, // #6A5ACD "slategray": {112, 128, 144}, // #708090 "slategrey": {112, 128, 144}, // #708090 "snow": {255, 250, 250}, // #FFFAFA "springgreen": {0, 255, 127}, // #00FF7F "steelblue": {70, 130, 180}, // #4682B4 "tan": {210, 180, 140}, // #D2B48C "teal": {0, 128, 128}, // #008080 "thistle": {216, 191, 216}, // #D8BFD8 "tomato": {255, 99, 71}, // #FF6347 "turquoise": {64, 224, 208}, // #40E0D0 "violet": {238, 130, 238}, // #EE82EE "wheat": {245, 222, 179}, // #F5DEB3 "white": {255, 255, 255}, // #FFFFFF "whitesmoke": {245, 245, 245}, // #F5F5F5 "yellow": {255, 255, 0}, // #FFFF00 "yellowgreen": {154, 205, 50}, // #9ACD32 } func Name2RGB(name string) RGB { if rgb, ok := namedRgbMap[strings.ToLower(name)]; ok { return RGB{ Red: rgb[0], Green: rgb[1], Blue: rgb[2], } } return RGB{} } var NamedColors = []string{ "currentcolor", "transparent", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgrey", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgrey", "lightgreen", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", } var ColorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`)