package sprite import ( "fmt" "image/color" "strconv" "strings" ) // Transparent is the color used for pixels that should not be drawn. var Transparent = color.NRGBA{0, 0, 0, 0} // ParseColor accepts: // // none | transparent | - -> fully transparent // #RGB #RGBA #RRGGBB #RRGGBBAA -> hex // rgb(r,g,b) rgba(r,g,b,a) -> 0-255 channels, alpha 0-255 or 0.0-1.0 // CSS named colors -> "red", "rebeccapurple", ... func ParseColor(s string) (color.NRGBA, error) { t := strings.ToLower(strings.TrimSpace(s)) if t == "" { return Transparent, fmt.Errorf("empty color value") } switch t { case "none", "transparent", "-": return Transparent, nil } if strings.HasPrefix(t, "#") { return parseHex(t) } if strings.HasPrefix(t, "rgb(") || strings.HasPrefix(t, "rgba(") { return parseRGBFunc(t) } if c, ok := cssColors[t]; ok { return c, nil } return Transparent, fmt.Errorf("unknown color %q (use #RRGGBB, rgb(r,g,b), a CSS color name, or 'none')", s) } func parseHex(t string) (color.NRGBA, error) { h := t[1:] var r, g, b, a uint64 var err error dup := func(s string) (uint64, error) { v, err := strconv.ParseUint(s, 16, 8) return v*16 + v, err } a = 255 switch len(h) { case 3, 4: if r, err = dup(h[0:1]); err == nil { if g, err = dup(h[1:2]); err == nil { b, err = dup(h[2:3]) } } if err == nil && len(h) == 4 { a, err = dup(h[3:4]) } case 6, 8: if r, err = strconv.ParseUint(h[0:2], 16, 8); err == nil { if g, err = strconv.ParseUint(h[2:4], 16, 8); err == nil { b, err = strconv.ParseUint(h[4:6], 16, 8) } } if err == nil && len(h) == 8 { a, err = strconv.ParseUint(h[6:8], 16, 8) } default: return Transparent, fmt.Errorf("hex color %q must be #RGB, #RGBA, #RRGGBB or #RRGGBBAA", t) } if err != nil { return Transparent, fmt.Errorf("invalid hex color %q", t) } return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}, nil } func parseRGBFunc(t string) (color.NRGBA, error) { open := strings.Index(t, "(") close := strings.Index(t, ")") if close < open { return Transparent, fmt.Errorf("invalid color %q: missing ')'", t) } parts := strings.Split(t[open+1:close], ",") if len(parts) != 3 && len(parts) != 4 { return Transparent, fmt.Errorf("invalid color %q: want rgb(r,g,b) or rgba(r,g,b,a)", t) } var ch [4]uint8 ch[3] = 255 for i, p := range parts { p = strings.TrimSpace(p) if i == 3 && strings.Contains(p, ".") { // CSS-style fractional alpha 0.0 - 1.0 f, err := strconv.ParseFloat(p, 64) if err != nil || f < 0 || f > 1 { return Transparent, fmt.Errorf("invalid alpha %q in %q (want 0.0-1.0 or 0-255)", p, t) } ch[3] = uint8(f*255 + 0.5) continue } v, err := strconv.ParseUint(p, 10, 8) if err != nil { return Transparent, fmt.Errorf("invalid channel %q in %q (want 0-255)", p, t) } ch[i] = uint8(v) } return color.NRGBA{ch[0], ch[1], ch[2], ch[3]}, nil } // FormatColor renders a color the way it should appear in a .sprite file. func FormatColor(c color.NRGBA) string { if c.A == 0 { return "none" } if c.A == 255 { return fmt.Sprintf("#%02X%02X%02X", c.R, c.G, c.B) } return fmt.Sprintf("#%02X%02X%02X%02X", c.R, c.G, c.B, c.A) } // cssColors is the full CSS Color Module Level 4 named-color list. var cssColors = map[string]color.NRGBA{ "aliceblue": {240, 248, 255, 255}, "antiquewhite": {250, 235, 215, 255}, "aqua": {0, 255, 255, 255}, "aquamarine": {127, 255, 212, 255}, "azure": {240, 255, 255, 255}, "beige": {245, 245, 220, 255}, "bisque": {255, 228, 196, 255}, "black": {0, 0, 0, 255}, "blanchedalmond": {255, 235, 205, 255}, "blue": {0, 0, 255, 255}, "blueviolet": {138, 43, 226, 255}, "brown": {165, 42, 42, 255}, "burlywood": {222, 184, 135, 255}, "cadetblue": {95, 158, 160, 255}, "chartreuse": {127, 255, 0, 255}, "chocolate": {210, 105, 30, 255}, "coral": {255, 127, 80, 255}, "cornflowerblue": {100, 149, 237, 255}, "cornsilk": {255, 248, 220, 255}, "crimson": {220, 20, 60, 255}, "cyan": {0, 255, 255, 255}, "darkblue": {0, 0, 139, 255}, "darkcyan": {0, 139, 139, 255}, "darkgoldenrod": {184, 134, 11, 255}, "darkgray": {169, 169, 169, 255}, "darkgreen": {0, 100, 0, 255}, "darkgrey": {169, 169, 169, 255}, "darkkhaki": {189, 183, 107, 255}, "darkmagenta": {139, 0, 139, 255}, "darkolivegreen": {85, 107, 47, 255}, "darkorange": {255, 140, 0, 255}, "darkorchid": {153, 50, 204, 255}, "darkred": {139, 0, 0, 255}, "darksalmon": {233, 150, 122, 255}, "darkseagreen": {143, 188, 143, 255}, "darkslateblue": {72, 61, 139, 255}, "darkslategray": {47, 79, 79, 255}, "darkslategrey": {47, 79, 79, 255}, "darkturquoise": {0, 206, 209, 255}, "darkviolet": {148, 0, 211, 255}, "deeppink": {255, 20, 147, 255}, "deepskyblue": {0, 191, 255, 255}, "dimgray": {105, 105, 105, 255}, "dimgrey": {105, 105, 105, 255}, "dodgerblue": {30, 144, 255, 255}, "firebrick": {178, 34, 34, 255}, "floralwhite": {255, 250, 240, 255}, "forestgreen": {34, 139, 34, 255}, "fuchsia": {255, 0, 255, 255}, "gainsboro": {220, 220, 220, 255}, "ghostwhite": {248, 248, 255, 255}, "gold": {255, 215, 0, 255}, "goldenrod": {218, 165, 32, 255}, "gray": {128, 128, 128, 255}, "green": {0, 128, 0, 255}, "greenyellow": {173, 255, 47, 255}, "grey": {128, 128, 128, 255}, "honeydew": {240, 255, 240, 255}, "hotpink": {255, 105, 180, 255}, "indianred": {205, 92, 92, 255}, "indigo": {75, 0, 130, 255}, "ivory": {255, 255, 240, 255}, "khaki": {240, 230, 140, 255}, "lavender": {230, 230, 250, 255}, "lavenderblush": {255, 240, 245, 255}, "lawngreen": {124, 252, 0, 255}, "lemonchiffon": {255, 250, 205, 255}, "lightblue": {173, 216, 230, 255}, "lightcoral": {240, 128, 128, 255}, "lightcyan": {224, 255, 255, 255}, "lightgoldenrodyellow": {250, 250, 210, 255}, "lightgray": {211, 211, 211, 255}, "lightgreen": {144, 238, 144, 255}, "lightgrey": {211, 211, 211, 255}, "lightpink": {255, 182, 193, 255}, "lightsalmon": {255, 160, 122, 255}, "lightseagreen": {32, 178, 170, 255}, "lightskyblue": {135, 206, 250, 255}, "lightslategray": {119, 136, 153, 255}, "lightslategrey": {119, 136, 153, 255}, "lightsteelblue": {176, 196, 222, 255}, "lightyellow": {255, 255, 224, 255}, "lime": {0, 255, 0, 255}, "limegreen": {50, 205, 50, 255}, "linen": {250, 240, 230, 255}, "magenta": {255, 0, 255, 255}, "maroon": {128, 0, 0, 255}, "mediumaquamarine": {102, 205, 170, 255}, "mediumblue": {0, 0, 205, 255}, "mediumorchid": {186, 85, 211, 255}, "mediumpurple": {147, 112, 219, 255}, "mediumseagreen": {60, 179, 113, 255}, "mediumslateblue": {123, 104, 238, 255}, "mediumspringgreen": {0, 250, 154, 255}, "mediumturquoise": {72, 209, 204, 255}, "mediumvioletred": {199, 21, 133, 255}, "midnightblue": {25, 25, 112, 255}, "mintcream": {245, 255, 250, 255}, "mistyrose": {255, 228, 225, 255}, "moccasin": {255, 228, 181, 255}, "navajowhite": {255, 222, 173, 255}, "navy": {0, 0, 128, 255}, "oldlace": {253, 245, 230, 255}, "olive": {128, 128, 0, 255}, "olivedrab": {107, 142, 35, 255}, "orange": {255, 165, 0, 255}, "orangered": {255, 69, 0, 255}, "orchid": {218, 112, 214, 255}, "palegoldenrod": {238, 232, 170, 255}, "palegreen": {152, 251, 152, 255}, "paleturquoise": {175, 238, 238, 255}, "palevioletred": {219, 112, 147, 255}, "papayawhip": {255, 239, 213, 255}, "peachpuff": {255, 218, 185, 255}, "peru": {205, 133, 63, 255}, "pink": {255, 192, 203, 255}, "plum": {221, 160, 221, 255}, "powderblue": {176, 224, 230, 255}, "purple": {128, 0, 128, 255}, "rebeccapurple": {102, 51, 153, 255}, "red": {255, 0, 0, 255}, "rosybrown": {188, 143, 143, 255}, "royalblue": {65, 105, 225, 255}, "saddlebrown": {139, 69, 19, 255}, "salmon": {250, 128, 114, 255}, "sandybrown": {244, 164, 96, 255}, "seagreen": {46, 139, 87, 255}, "seashell": {255, 245, 238, 255}, "sienna": {160, 82, 45, 255}, "silver": {192, 192, 192, 255}, "skyblue": {135, 206, 235, 255}, "slateblue": {106, 90, 205, 255}, "slategray": {112, 128, 144, 255}, "slategrey": {112, 128, 144, 255}, "snow": {255, 250, 250, 255}, "springgreen": {0, 255, 127, 255}, "steelblue": {70, 130, 180, 255}, "tan": {210, 180, 140, 255}, "teal": {0, 128, 128, 255}, "thistle": {216, 191, 216, 255}, "tomato": {255, 99, 71, 255}, "turquoise": {64, 224, 208, 255}, "violet": {238, 130, 238, 255}, "wheat": {245, 222, 179, 255}, "white": {255, 255, 255, 255}, "whitesmoke": {245, 245, 245, 255}, "yellow": {255, 255, 0, 255}, "yellowgreen": {154, 205, 50, 255}, }