From 9eab9205478ae056000918098bfc9e19a0052feb Mon Sep 17 00:00:00 2001 From: Florian Pigorsch Date: Sun, 21 Apr 2024 18:01:58 +0200 Subject: [PATCH] use external color parser package --- color.go | 55 ++++++++------------------------------------------- color_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 ++ 4 files changed, 58 insertions(+), 47 deletions(-) create mode 100644 color_test.go diff --git a/color.go b/color.go index 7a01012..e4b7bcb 100644 --- a/color.go +++ b/color.go @@ -6,58 +6,19 @@ package sm import ( - "fmt" "image/color" - "regexp" - "strings" + + "github.com/mazznoer/csscolorparser" ) -// ParseColorString parses hex color strings (i.e. `0xRRGGBB`, `#RRGGBB`, `0xRRGGBBAA`, `#RRGGBBAA`), and names colors (e.g. 'black', 'blue', ...) +// ParseColorString parses hex color strings (i.e. `#RRGGBB`, `RRGGBBAA`, `#RRGGBBAA`), and named colors (e.g. 'black', 'blue', ...) func ParseColorString(s string) (color.Color, error) { - s = strings.ToLower(strings.TrimSpace(s)) - - re := regexp.MustCompile(`^(0x|#)([A-Fa-f0-9]{6})$`) - matches := re.FindStringSubmatch(s) - if matches != nil { - var r, g, b int - fmt.Sscanf(matches[2], "%2x%2x%2x", &r, &g, &b) - return color.RGBA{uint8(r), uint8(g), uint8(b), 0xff}, nil - } - - re = regexp.MustCompile(`^(0x|#)([A-Fa-f0-9]{8})$`) - matches = re.FindStringSubmatch(s) - if matches != nil { - var r, g, b, a int - fmt.Sscanf(matches[2], "%2x%2x%2x%2x", &r, &g, &b, &a) - rr := float64(r) * float64(a) / 256.0 - gg := float64(g) * float64(a) / 256.0 - bb := float64(b) * float64(a) / 256.0 - return color.RGBA{uint8(rr), uint8(gg), uint8(bb), uint8(a)}, nil - } - - switch s { - case "black": - return color.RGBA{0x00, 0x00, 0x00, 0xff}, nil - case "blue": - return color.RGBA{0x00, 0x00, 0xff, 0xff}, nil - case "brown": - return color.RGBA{0x96, 0x4b, 0x00, 0xff}, nil - case "green": - return color.RGBA{0x00, 0xff, 0x00, 0xff}, nil - case "orange": - return color.RGBA{0xff, 0x7f, 0x00, 0xff}, nil - case "purple": - return color.RGBA{0x7f, 0x00, 0x7f, 0xff}, nil - case "red": - return color.RGBA{0xff, 0x00, 0x00, 0xff}, nil - case "yellow": - return color.RGBA{0xff, 0xff, 0x00, 0xff}, nil - case "white": - return color.RGBA{0xff, 0xff, 0xff, 0xff}, nil - case "transparent": - return color.RGBA{0x00, 0x00, 0x00, 0x00}, nil + if col, err := csscolorparser.Parse(s); err != nil { + return nil, err + } else { + r, g, b, a := col.RGBA255() + return color.RGBA{r, g, b, a}, nil } - return color.Transparent, fmt.Errorf("cannot parse color string '%s'", s) } // Luminance computes the luminance (~ brightness) of the given color. Range: 0.0 for black to 1.0 for white. diff --git a/color_test.go b/color_test.go new file mode 100644 index 0000000..6aa96aa --- /dev/null +++ b/color_test.go @@ -0,0 +1,47 @@ +package sm + +import ( + "image/color" + "testing" +) + +type string_color_err struct { + input string + expected_color color.Color + expected_error bool +} + +func TestParseColor(t *testing.T) { + for _, test := range []string_color_err{ + {"WHITE", color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}, false}, + {"white", color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}, false}, + {"yellow", color.RGBA{0xFF, 0xFF, 0x00, 0xFF}, false}, + {"transparent", color.RGBA{0x00, 0x00, 0x00, 0x00}, false}, + {"#FF00FF42", color.RGBA{0xFF, 0x00, 0xFF, 0x42}, false}, + {"#ff00ff42", color.RGBA{0xFF, 0x00, 0xFF, 0x42}, false}, + {"#ff00ff", color.RGBA{0xFF, 0x00, 0xFF, 0xFF}, false}, + {"#f0f", color.RGBA{0xFF, 0x00, 0xFF, 0xFF}, false}, + {"FF00FF42", color.RGBA{0xFF, 0x00, 0xFF, 0x42}, false}, + {"ff00ff42", color.RGBA{0xFF, 0x00, 0xFF, 0x42}, false}, + {"ff00ff", color.RGBA{0xFF, 0x00, 0xFF, 0xFF}, false}, + {"f0f", color.RGBA{0xFF, 0x00, 0xFF, 0xFF}, false}, + {"bad-name", color.RGBA{0x00, 0x00, 0x00, 0x00}, true}, + {"#FF00F", color.RGBA{0x00, 0x00, 0x00, 0x00}, true}, + {"#GGGGGG", color.RGBA{0x00, 0x00, 0x00, 0x00}, true}, + {"", color.RGBA{0x00, 0x00, 0x00, 0x00}, true}, + } { + c, err := ParseColorString(test.input) + if test.expected_error { + if err == nil { + t.Errorf("error expected when parsing '%s'", test.input) + } + } else { + if err != nil { + t.Errorf("unexpected error when parsing '%s': %v", test.input, err) + } + if c != test.expected_color { + t.Errorf("unexpected color when parsing '%s': %v expected: %v", test.input, c, test.expected_color) + } + } + } +} diff --git a/go.mod b/go.mod index 298291d..f55976b 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( require ( github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/mazznoer/csscolorparser v0.1.3 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index 7ea5f63..22dec2a 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1Ix github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/joeshaw/gengen v0.0.0-20190604015154-c77d87825f5a/go.mod h1:v2qvRL8Xwk4OlARK6gPlf2JreZXzv0dYp/8+kUJ0y7Q= +github.com/mazznoer/csscolorparser v0.1.3 h1:vug4zh6loQxAUxfU1DZEu70gTPufDPspamZlHAkKcxE= +github.com/mazznoer/csscolorparser v0.1.3/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=