265 lines
12 KiB
C
265 lines
12 KiB
C
#include "color_parser.h"
|
|
#include "tkc/str.h"
|
|
#include "tkc/mem.h"
|
|
#include "tkc/utils.h"
|
|
|
|
typedef struct _color_map_t {
|
|
const char* name;
|
|
const char* value;
|
|
} color_map_t;
|
|
|
|
static color_map_t const colors_map[] = {{"aliceblue", "#f0f8ff"},
|
|
{"antiquewhite", "#faebd7"},
|
|
{"aqua", "#00ffff"},
|
|
{"aquamarine", "#7fffd4"},
|
|
{"azure", "#f0ffff"},
|
|
{"beige", "#f5f5dc"},
|
|
{"bisque", "#ffe4c4"},
|
|
{"black", "#000000"},
|
|
{"blanchedalmond", "#ffebcd"},
|
|
{"blue", "#0000ff"},
|
|
{"blueviolet", "#8a2be2"},
|
|
{"brown", "#a52a2a"},
|
|
{"burlywood", "#deb887"},
|
|
{"cadetblue", "#5f9ea0"},
|
|
{"chartreuse", "#7fff00"},
|
|
{"chocolate", "#d2691e"},
|
|
{"coral", "#ff7f50"},
|
|
{"cornflowerblue", "#6495ed"},
|
|
{"cornsilk", "#fff8dc"},
|
|
{"crimson", "#dc143c"},
|
|
{"cyan", "#00ffff"},
|
|
{"darkblue", "#00008b"},
|
|
{"darkcyan", "#008b8b"},
|
|
{"darkgoldenrod", "#b8860b"},
|
|
{"darkgray", "#a9a9a9"},
|
|
{"darkgreen", "#006400"},
|
|
{"darkkhaki", "#bdb76b"},
|
|
{"darkmagenta", "#8b008b"},
|
|
{"darkolivegreen", "#556b2f"},
|
|
{"darkorange", "#ff8c00"},
|
|
{"darkorchid", "#9932cc"},
|
|
{"darkred", "#8b0000"},
|
|
{"darksalmon", "#e9967a"},
|
|
{"darkseagreen", "#8fbc8f"},
|
|
{"darkslateblue", "#483d8b"},
|
|
{"darkslategray", "#2f4f4f"},
|
|
{"darkturquoise", "#00ced1"},
|
|
{"darkviolet", "#9400d3"},
|
|
{"deeppink", "#ff1493"},
|
|
{"deepskyblue", "#00bfff"},
|
|
{"dimgray", "#696969"},
|
|
{"dodgerblue", "#1e90ff"},
|
|
{"firebrick", "#b22222"},
|
|
{"floralwhite", "#fffaf0"},
|
|
{"forestgreen", "#228b22"},
|
|
{"fuchsia", "#ff00ff"},
|
|
{"gainsboro", "#dcdcdc"},
|
|
{"ghostwhite", "#f8f8ff"},
|
|
{"gold", "#ffd700"},
|
|
{"goldenrod", "#daa520"},
|
|
{"gray", "#bebebe"},
|
|
{"green", "#008000"},
|
|
{"greenyellow", "#adff2f"},
|
|
{"honeydew", "#f0fff0"},
|
|
{"hotpink", "#ff69b4"},
|
|
{"indianred", "#cd5c5c"},
|
|
{"indigo", "#4b0082"},
|
|
{"ivory", "#fffff0"},
|
|
{"khaki", "#f0d58c"},
|
|
{"lavender", "#e6e6fa"},
|
|
{"lavenderblush", "#fff0f5"},
|
|
{"lawngreen", "#7cfc00"},
|
|
{"lemonchiffon", "#fffacd"},
|
|
{"lightblue", "#add8e6"},
|
|
{"lightcoral", "#f08080"},
|
|
{"lightcyan", "#e0ffff"},
|
|
{"lightgoldenrodyellow", "#fafad2"},
|
|
{"lightgreen", "#90ee90"},
|
|
{"lightgrey", "#d3d3d3"},
|
|
{"lightpink", "#ffb6c1"},
|
|
{"lightsalmon", "#ffa07a"},
|
|
{"lightseagreen", "#20b2aa"},
|
|
{"lightskyblue", "#87cefa"},
|
|
{"lightslategray", "#778899"},
|
|
{"lightsteelblue", "#b0c4de"},
|
|
{"lightyellow", "#ffffe0"},
|
|
{"lime", "#00ff00"},
|
|
{"limegreen", "#32cd32"},
|
|
{"linen", "#faf0e6"},
|
|
{"magenta", "#ff00ff"},
|
|
{"maroon", "#800000"},
|
|
{"mediumaquamarine", "#66cdaa"},
|
|
{"mediumblue", "#0000cd"},
|
|
{"mediumorchid", "#ba55d3"},
|
|
{"mediumpurple", "#9370db"},
|
|
{"mediumseagreen", "#3cb371"},
|
|
{"mediumslateblue", "#7b68ee"},
|
|
{"mediumspringgreen", "#00fa9a"},
|
|
{"mediumturquoise", "#48d1cc"},
|
|
{"mediumvioletred", "#c71585"},
|
|
{"midnightblue", "#191970"},
|
|
{"mintcream", "#f5fffa"},
|
|
{"mistyrose", "#ffe4e1"},
|
|
{"moccasin", "#ffe4b5"},
|
|
{"navajowhite", "#ffdead"},
|
|
{"navy", "#000080"},
|
|
{"oldlace", "#fdf5e6"},
|
|
{"olive", "#808000"},
|
|
{"olivedrab", "#6b8e23"},
|
|
{"orange", "#ffa500"},
|
|
{"orangered", "#ff4500"},
|
|
{"orchid", "#da70d6"},
|
|
{"palegoldenrod", "#eee8aa"},
|
|
{"palegreen", "#98fb98"},
|
|
{"paleturquoise", "#afeeee"},
|
|
{"palevioletred", "#db7093"},
|
|
{"papayawhip", "#ffefd5"},
|
|
{"peachpuff", "#ffdab9"},
|
|
{"peru", "#cd853f"},
|
|
{"pink", "#ffc0cb"},
|
|
{"plum", "#dda0dd"},
|
|
{"powderblue", "#b0e0e6"},
|
|
{"purple", "#800080"},
|
|
{"red", "#ff0000"},
|
|
{"rosybrown", "#bc8f8f"},
|
|
{"royalblue", "#4169e1"},
|
|
{"saddlebrown", "#8b4513"},
|
|
{"salmon", "#fa8072"},
|
|
{"sandybrown", "#f4a460"},
|
|
{"seagreen", "#2e8b57"},
|
|
{"seashell", "#fff5ee"},
|
|
{"sienna", "#a0522d"},
|
|
{"silver", "#c0c0c0"},
|
|
{"skyblue", "#87ceeb"},
|
|
{"slateblue", "#6a5acd"},
|
|
{"slategray", "#708090"},
|
|
{"snow", "#fffafa"},
|
|
{"springgreen", "#00ff7f"},
|
|
{"steelblue", "#4682b4"},
|
|
{"tan", "#d2b48c"},
|
|
{"teal", "#008080"},
|
|
{"thistle", "#d8bfd8"},
|
|
{"tomato", "#ff6347"},
|
|
{"turquoise", "#40e0d0"},
|
|
{"violet", "#ee82ee"},
|
|
{"wheat", "#f5deb3"},
|
|
{"white", "#ffffff"},
|
|
{"whitesmoke", "#f5f5f5"},
|
|
{"yellow", "#ffff00"},
|
|
{"yellowgreen", "#9acd32"}};
|
|
|
|
static int compare_color(const color_map_t* a, const color_map_t* b) {
|
|
return strcasecmp(a->name, b->name);
|
|
}
|
|
|
|
static const char* map_name_to_value(const char* name) {
|
|
color_map_t color_map;
|
|
color_map.name = name;
|
|
color_map.value = NULL;
|
|
|
|
color_map_t* ret = (color_map_t*)bsearch(&color_map, colors_map, ARRAY_SIZE(colors_map),
|
|
sizeof(color_map_t), (tk_compare_t)compare_color);
|
|
|
|
return ret ? ret->value : NULL;
|
|
}
|
|
|
|
static bool_t color_parse_rgba(const char* color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
|
|
uint32_t len = strlen(color);
|
|
return_value_if_fail(len > 6, FALSE);
|
|
|
|
int ir = 0;
|
|
int ig = 0;
|
|
int ib = 0;
|
|
float fa = 1;
|
|
|
|
if (strstr(color, "rgba") != NULL) {
|
|
tk_sscanf(color, "rgba(%d,%d,%d,%f)", &ir, &ig, &ib, &fa);
|
|
} else {
|
|
tk_sscanf(color, "rgb(%d,%d,%d)", &ir, &ig, &ib);
|
|
}
|
|
|
|
*r = ir & 0xff;
|
|
*g = ig & 0xff;
|
|
*b = ib & 0xff;
|
|
*a = (int)(fa * 255) & 0xff;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool_t color_parse_hex(const char* color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
|
|
uint32_t len = strlen(color);
|
|
return_value_if_fail(len > 6, FALSE);
|
|
|
|
int ir = 0;
|
|
int ig = 0;
|
|
int ib = 0;
|
|
int ia = 0xff;
|
|
|
|
if (len < 8) {
|
|
tk_sscanf(color, "#%02x%02x%02x", &ir, &ig, &ib);
|
|
} else {
|
|
tk_sscanf(color, "#%02x%02x%02x%02x", &ir, &ig, &ib, &ia);
|
|
}
|
|
|
|
*r = ir & 0xff;
|
|
*g = ig & 0xff;
|
|
*b = ib & 0xff;
|
|
*a = ia & 0xff;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool_t color_parse_impl(const char* color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
|
|
str_t s;
|
|
str_t* str;
|
|
bool_t ret = FALSE;
|
|
return_value_if_fail(color != NULL && r != NULL && g != NULL && b != NULL && a != NULL, FALSE);
|
|
|
|
*r = 0;
|
|
*b = 0;
|
|
*g = 0;
|
|
*a = 0;
|
|
|
|
str = str_init(&s, 10);
|
|
str_set(str, color);
|
|
|
|
if (str_start_with(str, "rgb")) {
|
|
str_to_lower(str);
|
|
str_replace(str, " ", "");
|
|
|
|
ret = color_parse_rgba(str->str, r, g, b, a);
|
|
} else {
|
|
const char* value = color[0] == '#' ? color : map_name_to_value(color);
|
|
|
|
if (value) {
|
|
str_set(str, value);
|
|
str_to_lower(str);
|
|
|
|
ret = color_parse_hex(str->str, r, g, b, a);
|
|
}
|
|
}
|
|
str_reset(str);
|
|
|
|
return ret;
|
|
}
|
|
|
|
color_t color_parse(const char* color) {
|
|
uint8_t r = 0;
|
|
uint8_t g = 0;
|
|
uint8_t b = 0;
|
|
uint8_t a = 0xff;
|
|
|
|
color_parse_impl(color, &r, &g, &b, &a);
|
|
|
|
return color_init(r, g, b, a);
|
|
}
|
|
|
|
color_t* color_from_str(color_t* c, const char* str) {
|
|
return_value_if_fail(c != NULL && str != NULL, NULL);
|
|
|
|
*c = color_parse(str);
|
|
|
|
return c;
|
|
}
|