You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

390 lines
7.8 KiB

14 years ago
//
// 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
);
}