1 changed files with 389 additions and 0 deletions
@ -0,0 +1,389 @@ |
|||
|
|||
//
|
|||
// color.h
|
|||
//
|
|||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
|||
//
|
|||
|
|||
#include <stdio.h> |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
|
|||
/*
|
|||
* Consume whitespace. |
|||
*/ |
|||
|
|||
#define WHITESPACE \ |
|||
while (' ' == *str) ++str; |
|||
|
|||
/*
|
|||
* Parse color channel value |
|||
*/ |
|||
|
|||
#define CHANNEL(NAME) \ |
|||
if (*str >= '0' && *str <= '9') { \ |
|||
do { \ |
|||
NAME *= 10; \ |
|||
NAME += *str++ - '0'; \ |
|||
} while (*str >= '0' && *str <= '9'); \ |
|||
} else { \ |
|||
return -1; \ |
|||
} \ |
|||
while (' ' == *str || ',' == *str) str++; |
|||
|
|||
/*
|
|||
* Named colors. |
|||
*/ |
|||
|
|||
static struct named_color { |
|||
char *name; |
|||
uint32_t val; |
|||
} named_colors[] = { |
|||
"transparent", 0xffffff00 |
|||
, "aliceblue", 0xf0f8ffff |
|||
, "antiquewhite", 0xfaebd7ff |
|||
, "aqua", 0x00ffffff |
|||
, "aquamarine", 0x7fffd4ff |
|||
, "azure", 0xf0ffffff |
|||
, "beige", 0xf5f5dcff |
|||
, "bisque", 0xffe4c4ff |
|||
, "black", 0x000000ff |
|||
, "blanchedalmond", 0xffebcdff |
|||
, "blue", 0x0000ffff |
|||
, "blueviolet", 0x8a2be2ff |
|||
, "brown", 0xa52a2aff |
|||
, "burlywood", 0xdeb887ff |
|||
, "cadetblue", 0x5f9ea0ff |
|||
, "chartreuse", 0x7fff00ff |
|||
, "chocolate", 0xd2691eff |
|||
, "coral", 0xff7f50ff |
|||
, "cornflowerblue", 0x6495edff |
|||
, "cornsilk", 0xfff8dcff |
|||
, "crimson", 0xdc143cff |
|||
, "cyan", 0x00ffffff |
|||
, "darkblue", 0x00008bff |
|||
, "darkcyan", 0x008b8bff |
|||
, "darkgoldenrod", 0xb8860bff |
|||
, "darkgray", 0xa9a9a9ff |
|||
, "darkgreen", 0x006400ff |
|||
, "darkkhaki", 0xbdb76bff |
|||
, "darkmagenta", 0x8b008bff |
|||
, "darkolivegreen", 0x556b2fff |
|||
, "darkorange", 0xff8c00ff |
|||
, "darkorchid", 0x9932ccff |
|||
, "darkred", 0x8b0000ff |
|||
, "darksalmon", 0xe9967aff |
|||
, "darkseagreen", 0x8fbc8fff |
|||
, "darkslateblue", 0x483d8bff |
|||
, "darkslategray", 0x2f4f4fff |
|||
, "darkturquoise", 0x00ced1ff |
|||
, "darkviolet", 0x9400d3ff |
|||
, "deeppink", 0xff1493ff |
|||
, "deepskyblue", 0x00bfffff |
|||
, "dimgray", 0x696969ff |
|||
, "dodgerblue", 0x1e90ffff |
|||
, "feldspar", 0xd19275ff |
|||
, "firebrick", 0xb22222ff |
|||
, "floralwhite", 0xfffaf0ff |
|||
, "forestgreen", 0x228b22ff |
|||
, "fuchsia", 0xff00ffff |
|||
, "gainsboro", 0xdcdcdcff |
|||
, "ghostwhite", 0xf8f8ffff |
|||
, "gold", 0xffd700ff |
|||
, "goldenrod", 0xdaa520ff |
|||
, "gray", 0x808080ff |
|||
, "green", 0x008000ff |
|||
, "greenyellow", 0xadff2fff |
|||
, "honeydew", 0xf0fff0ff |
|||
, "hotpink", 0xff69b4ff |
|||
, "indianred ", 0xcd5c5cff |
|||
, "indigo ", 0x4b0082ff |
|||
, "ivory", 0xfffff0ff |
|||
, "khaki", 0xf0e68cff |
|||
, "lavender", 0xe6e6faff |
|||
, "lavenderblush", 0xfff0f5ff |
|||
, "lawngreen", 0x7cfc00ff |
|||
, "lemonchiffon", 0xfffacdff |
|||
, "lightblue", 0xadd8e6ff |
|||
, "lightcoral", 0xf08080ff |
|||
, "lightcyan", 0xe0ffffff |
|||
, "lightgoldenrodyellow", 0xfafad2ff |
|||
, "lightgrey", 0xd3d3d3ff |
|||
, "lightgreen", 0x90ee90ff |
|||
, "lightpink", 0xffb6c1ff |
|||
, "lightsalmon", 0xffa07aff |
|||
, "lightseagreen", 0x20b2aaff |
|||
, "lightskyblue", 0x87cefaff |
|||
, "lightslateblue", 0x8470ffff |
|||
, "lightslategray", 0x778899ff |
|||
, "lightsteelblue", 0xb0c4deff |
|||
, "lightyellow", 0xffffe0ff |
|||
, "lime", 0x00ff00ff |
|||
, "limegreen", 0x32cd32ff |
|||
, "linen", 0xfaf0e6ff |
|||
, "magenta", 0xff00ffff |
|||
, "maroon", 0x800000ff |
|||
, "mediumaquamarine", 0x66cdaaff |
|||
, "mediumblue", 0x0000cdff |
|||
, "mediumorchid", 0xba55d3ff |
|||
, "mediumpurple", 0x9370d8ff |
|||
, "mediumseagreen", 0x3cb371ff |
|||
, "mediumslateblue", 0x7b68eeff |
|||
, "mediumspringgreen", 0x00fa9aff |
|||
, "mediumturquoise", 0x48d1ccff |
|||
, "mediumvioletred", 0xc71585ff |
|||
, "midnightblue", 0x191970ff |
|||
, "mintcream", 0xf5fffaff |
|||
, "mistyrose", 0xffe4e1ff |
|||
, "moccasin", 0xffe4b5ff |
|||
, "navajowhite", 0xffdeadff |
|||
, "navy", 0x000080ff |
|||
, "oldlace", 0xfdf5e6ff |
|||
, "olive", 0x808000ff |
|||
, "olivedrab", 0x6b8e23ff |
|||
, "orange", 0xffa500ff |
|||
, "orangered", 0xff4500ff |
|||
, "orchid", 0xda70d6ff |
|||
, "palegoldenrod", 0xeee8aaff |
|||
, "palegreen", 0x98fb98ff |
|||
, "paleturquoise", 0xafeeeeff |
|||
, "palevioletred", 0xd87093ff |
|||
, "papayawhip", 0xffefd5ff |
|||
, "peachpuff", 0xffdab9ff |
|||
, "peru", 0xcd853fff |
|||
, "pink", 0xffc0cbff |
|||
, "plum", 0xdda0ddff |
|||
, "powderblue", 0xb0e0e6ff |
|||
, "purple", 0x800080ff |
|||
, "red", 0xff0000ff |
|||
, "rosybrown", 0xbc8f8fff |
|||
, "royalblue", 0x4169e1ff |
|||
, "saddlebrown", 0x8b4513ff |
|||
, "salmon", 0xfa8072ff |
|||
, "sandybrown", 0xf4a460ff |
|||
, "seagreen", 0x2e8b57ff |
|||
, "seashell", 0xfff5eeff |
|||
, "sienna", 0xa0522dff |
|||
, "silver", 0xc0c0c0ff |
|||
, "skyblue", 0x87ceebff |
|||
, "slateblue", 0x6a5acdff |
|||
, "slategray", 0x708090ff |
|||
, "snow", 0xfffafaff |
|||
, "springgreen", 0x00ff7fff |
|||
, "steelblue", 0x4682b4ff |
|||
, "tan", 0xd2b48cff |
|||
, "teal", 0x008080ff |
|||
, "thistle", 0xd8bfd8ff |
|||
, "tomato", 0xff6347ff |
|||
, "turquoise", 0x40e0d0ff |
|||
, "violet", 0xee82eeff |
|||
, "violetred", 0xd02090ff |
|||
, "wheat", 0xf5deb3ff |
|||
, "white", 0xffffffff |
|||
, "whitesmoke", 0xf5f5f5ff |
|||
, "yellow", 0xffff00ff |
|||
, "yellowgreen", 0x9acd32ff |
|||
, NULL, NULL |
|||
}; |
|||
|
|||
/*
|
|||
* Hex digit int val. |
|||
*/ |
|||
|
|||
static int |
|||
h(char c) { |
|||
switch (c) { |
|||
case '0': |
|||
case '1': |
|||
case '2': |
|||
case '3': |
|||
case '4': |
|||
case '5': |
|||
case '6': |
|||
case '7': |
|||
case '8': |
|||
case '9': |
|||
return c - '0'; |
|||
case 'a': |
|||
case 'b': |
|||
case 'c': |
|||
case 'd': |
|||
case 'e': |
|||
case 'f': |
|||
return (c - 'a') + 10; |
|||
case 'A': |
|||
case 'B': |
|||
case 'C': |
|||
case 'D': |
|||
case 'E': |
|||
case 'F': |
|||
return (c - 'A') + 10; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/*
|
|||
* Return rgba from (r,g,b,a). |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { |
|||
return |
|||
r << 24 |
|||
| g << 16 |
|||
| b << 8 |
|||
| a; |
|||
} |
|||
|
|||
/*
|
|||
* Return rgba from (r,g,b). |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { |
|||
return rgba_from_rgba(r, g, b, 0); |
|||
} |
|||
|
|||
/*
|
|||
* Return rgb from "#RRGGBB". |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_hex6_string(const char *str) { |
|||
return rgba_from_rgb( |
|||
(h(str[0]) << 4) + h(str[1]) |
|||
, (h(str[2]) << 4) + h(str[3]) |
|||
, (h(str[4]) << 4) + h(str[5]) |
|||
); |
|||
} |
|||
|
|||
/*
|
|||
* Return rgb from "#RGB" |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_hex3_string(const char *str) { |
|||
return rgba_from_rgb( |
|||
(h(str[0]) << 4) + h(str[0]) |
|||
, (h(str[1]) << 4) + h(str[1]) |
|||
, (h(str[2]) << 4) + h(str[2]) |
|||
); |
|||
} |
|||
|
|||
/*
|
|||
* Return rgb from "rgb()" |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_rgb_string(const char *str) { |
|||
if (str == strnstr(str, "rgb(", 4)) { |
|||
str += 4; |
|||
WHITESPACE; |
|||
uint8_t r = 0, g = 0, b = 0; |
|||
CHANNEL(r); |
|||
CHANNEL(g); |
|||
CHANNEL(b); |
|||
return rgba_from_rgb(r, g, b); |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
/*
|
|||
* Return rgb from "rgba()" |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_rgba_string(const char *str) { |
|||
if (str == strnstr(str, "rgba(", 5)) { |
|||
str += 5; |
|||
WHITESPACE; |
|||
uint8_t r = 0, g = 0, b = 0; |
|||
float a = 0; |
|||
CHANNEL(r); |
|||
CHANNEL(g); |
|||
CHANNEL(b); |
|||
// TODO: less strict
|
|||
if ('1' == *str) { |
|||
a = 1; |
|||
} else { |
|||
if ('0' == *str) a = 0, ++str; |
|||
if ('.' == *str) { |
|||
++str; |
|||
float n = .1; |
|||
while (*str >= '0' && *str <= '9') { |
|||
a += (*str++ - '0') * n; |
|||
n *= .1; |
|||
} |
|||
} |
|||
} |
|||
return rgba_from_rgba(r, g, b, a * 255); |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
/*
|
|||
* Return rgb from: |
|||
* |
|||
* - "#RGB" |
|||
* - "#RRGGBB" |
|||
* |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_hex_string(const char *str) { |
|||
size_t len = strlen(str); |
|||
if (6 == len) return rgba_from_hex6_string(str); |
|||
if (3 == len) return rgba_from_hex3_string(str); |
|||
return -1; |
|||
} |
|||
|
|||
/*
|
|||
* Return named color value. |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_name_string(const char *str) { |
|||
int i = 0; |
|||
struct named_color color; |
|||
while ((color = named_colors[i++]).name) { |
|||
if (*str == *color.name && 0 == strcmp(str, color.name)) |
|||
return color.val; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
/*
|
|||
* Return rgb from: |
|||
* |
|||
* - #RGB |
|||
* - #RRGGBB |
|||
* - rgb(r,g,b) |
|||
* - rgba(r,g,b,a) |
|||
* - name |
|||
* |
|||
*/ |
|||
|
|||
int32_t |
|||
rgba_from_string(const char *str) { |
|||
if ('#' == str[0]) |
|||
return rgba_from_hex_string(++str); |
|||
if (str == strnstr(str, "rgba", 4)) |
|||
return rgba_from_rgba_string(str); |
|||
if (str == strnstr(str, "rgb", 3)) |
|||
return rgba_from_rgb_string(str); |
|||
return rgba_from_name_string(str); |
|||
} |
|||
|
|||
/*
|
|||
* Inspect the given rgba color. |
|||
*/ |
|||
|
|||
void |
|||
rgba_inspect(int32_t rgba) { |
|||
printf("rgba(%d,%d,%d,%d)\n" |
|||
, rgba >> 24 & 0xFF |
|||
, rgba >> 16 & 0xFF |
|||
, rgba >> 8 & 0xFF |
|||
, rgba & 0xFF |
|||
); |
|||
} |
Loading…
Reference in new issue