00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025 #include <strings.h>
00026 #include "libavutil/avutil.h"
00027 #include "libavutil/avstring.h"
00028 #include "libavutil/random_seed.h"
00029 #include "parseutils.h"
00030
00031 typedef struct {
00032 const char *name;
00033 uint8_t rgb_color[3];
00034 } ColorEntry;
00035
00036 static ColorEntry color_table[] = {
00037 { "AliceBlue", { 0xF0, 0xF8, 0xFF } },
00038 { "AntiqueWhite", { 0xFA, 0xEB, 0xD7 } },
00039 { "Aqua", { 0x00, 0xFF, 0xFF } },
00040 { "Aquamarine", { 0x7F, 0xFF, 0xD4 } },
00041 { "Azure", { 0xF0, 0xFF, 0xFF } },
00042 { "Beige", { 0xF5, 0xF5, 0xDC } },
00043 { "Bisque", { 0xFF, 0xE4, 0xC4 } },
00044 { "Black", { 0x00, 0x00, 0x00 } },
00045 { "BlanchedAlmond", { 0xFF, 0xEB, 0xCD } },
00046 { "Blue", { 0x00, 0x00, 0xFF } },
00047 { "BlueViolet", { 0x8A, 0x2B, 0xE2 } },
00048 { "Brown", { 0xA5, 0x2A, 0x2A } },
00049 { "BurlyWood", { 0xDE, 0xB8, 0x87 } },
00050 { "CadetBlue", { 0x5F, 0x9E, 0xA0 } },
00051 { "Chartreuse", { 0x7F, 0xFF, 0x00 } },
00052 { "Chocolate", { 0xD2, 0x69, 0x1E } },
00053 { "Coral", { 0xFF, 0x7F, 0x50 } },
00054 { "CornflowerBlue", { 0x64, 0x95, 0xED } },
00055 { "Cornsilk", { 0xFF, 0xF8, 0xDC } },
00056 { "Crimson", { 0xDC, 0x14, 0x3C } },
00057 { "Cyan", { 0x00, 0xFF, 0xFF } },
00058 { "DarkBlue", { 0x00, 0x00, 0x8B } },
00059 { "DarkCyan", { 0x00, 0x8B, 0x8B } },
00060 { "DarkGoldenRod", { 0xB8, 0x86, 0x0B } },
00061 { "DarkGray", { 0xA9, 0xA9, 0xA9 } },
00062 { "DarkGreen", { 0x00, 0x64, 0x00 } },
00063 { "DarkKhaki", { 0xBD, 0xB7, 0x6B } },
00064 { "DarkMagenta", { 0x8B, 0x00, 0x8B } },
00065 { "DarkOliveGreen", { 0x55, 0x6B, 0x2F } },
00066 { "Darkorange", { 0xFF, 0x8C, 0x00 } },
00067 { "DarkOrchid", { 0x99, 0x32, 0xCC } },
00068 { "DarkRed", { 0x8B, 0x00, 0x00 } },
00069 { "DarkSalmon", { 0xE9, 0x96, 0x7A } },
00070 { "DarkSeaGreen", { 0x8F, 0xBC, 0x8F } },
00071 { "DarkSlateBlue", { 0x48, 0x3D, 0x8B } },
00072 { "DarkSlateGray", { 0x2F, 0x4F, 0x4F } },
00073 { "DarkTurquoise", { 0x00, 0xCE, 0xD1 } },
00074 { "DarkViolet", { 0x94, 0x00, 0xD3 } },
00075 { "DeepPink", { 0xFF, 0x14, 0x93 } },
00076 { "DeepSkyBlue", { 0x00, 0xBF, 0xFF } },
00077 { "DimGray", { 0x69, 0x69, 0x69 } },
00078 { "DodgerBlue", { 0x1E, 0x90, 0xFF } },
00079 { "FireBrick", { 0xB2, 0x22, 0x22 } },
00080 { "FloralWhite", { 0xFF, 0xFA, 0xF0 } },
00081 { "ForestGreen", { 0x22, 0x8B, 0x22 } },
00082 { "Fuchsia", { 0xFF, 0x00, 0xFF } },
00083 { "Gainsboro", { 0xDC, 0xDC, 0xDC } },
00084 { "GhostWhite", { 0xF8, 0xF8, 0xFF } },
00085 { "Gold", { 0xFF, 0xD7, 0x00 } },
00086 { "GoldenRod", { 0xDA, 0xA5, 0x20 } },
00087 { "Gray", { 0x80, 0x80, 0x80 } },
00088 { "Green", { 0x00, 0x80, 0x00 } },
00089 { "GreenYellow", { 0xAD, 0xFF, 0x2F } },
00090 { "HoneyDew", { 0xF0, 0xFF, 0xF0 } },
00091 { "HotPink", { 0xFF, 0x69, 0xB4 } },
00092 { "IndianRed", { 0xCD, 0x5C, 0x5C } },
00093 { "Indigo", { 0x4B, 0x00, 0x82 } },
00094 { "Ivory", { 0xFF, 0xFF, 0xF0 } },
00095 { "Khaki", { 0xF0, 0xE6, 0x8C } },
00096 { "Lavender", { 0xE6, 0xE6, 0xFA } },
00097 { "LavenderBlush", { 0xFF, 0xF0, 0xF5 } },
00098 { "LawnGreen", { 0x7C, 0xFC, 0x00 } },
00099 { "LemonChiffon", { 0xFF, 0xFA, 0xCD } },
00100 { "LightBlue", { 0xAD, 0xD8, 0xE6 } },
00101 { "LightCoral", { 0xF0, 0x80, 0x80 } },
00102 { "LightCyan", { 0xE0, 0xFF, 0xFF } },
00103 { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
00104 { "LightGrey", { 0xD3, 0xD3, 0xD3 } },
00105 { "LightGreen", { 0x90, 0xEE, 0x90 } },
00106 { "LightPink", { 0xFF, 0xB6, 0xC1 } },
00107 { "LightSalmon", { 0xFF, 0xA0, 0x7A } },
00108 { "LightSeaGreen", { 0x20, 0xB2, 0xAA } },
00109 { "LightSkyBlue", { 0x87, 0xCE, 0xFA } },
00110 { "LightSlateGray", { 0x77, 0x88, 0x99 } },
00111 { "LightSteelBlue", { 0xB0, 0xC4, 0xDE } },
00112 { "LightYellow", { 0xFF, 0xFF, 0xE0 } },
00113 { "Lime", { 0x00, 0xFF, 0x00 } },
00114 { "LimeGreen", { 0x32, 0xCD, 0x32 } },
00115 { "Linen", { 0xFA, 0xF0, 0xE6 } },
00116 { "Magenta", { 0xFF, 0x00, 0xFF } },
00117 { "Maroon", { 0x80, 0x00, 0x00 } },
00118 { "MediumAquaMarine", { 0x66, 0xCD, 0xAA } },
00119 { "MediumBlue", { 0x00, 0x00, 0xCD } },
00120 { "MediumOrchid", { 0xBA, 0x55, 0xD3 } },
00121 { "MediumPurple", { 0x93, 0x70, 0xD8 } },
00122 { "MediumSeaGreen", { 0x3C, 0xB3, 0x71 } },
00123 { "MediumSlateBlue", { 0x7B, 0x68, 0xEE } },
00124 { "MediumSpringGreen", { 0x00, 0xFA, 0x9A } },
00125 { "MediumTurquoise", { 0x48, 0xD1, 0xCC } },
00126 { "MediumVioletRed", { 0xC7, 0x15, 0x85 } },
00127 { "MidnightBlue", { 0x19, 0x19, 0x70 } },
00128 { "MintCream", { 0xF5, 0xFF, 0xFA } },
00129 { "MistyRose", { 0xFF, 0xE4, 0xE1 } },
00130 { "Moccasin", { 0xFF, 0xE4, 0xB5 } },
00131 { "NavajoWhite", { 0xFF, 0xDE, 0xAD } },
00132 { "Navy", { 0x00, 0x00, 0x80 } },
00133 { "OldLace", { 0xFD, 0xF5, 0xE6 } },
00134 { "Olive", { 0x80, 0x80, 0x00 } },
00135 { "OliveDrab", { 0x6B, 0x8E, 0x23 } },
00136 { "Orange", { 0xFF, 0xA5, 0x00 } },
00137 { "OrangeRed", { 0xFF, 0x45, 0x00 } },
00138 { "Orchid", { 0xDA, 0x70, 0xD6 } },
00139 { "PaleGoldenRod", { 0xEE, 0xE8, 0xAA } },
00140 { "PaleGreen", { 0x98, 0xFB, 0x98 } },
00141 { "PaleTurquoise", { 0xAF, 0xEE, 0xEE } },
00142 { "PaleVioletRed", { 0xD8, 0x70, 0x93 } },
00143 { "PapayaWhip", { 0xFF, 0xEF, 0xD5 } },
00144 { "PeachPuff", { 0xFF, 0xDA, 0xB9 } },
00145 { "Peru", { 0xCD, 0x85, 0x3F } },
00146 { "Pink", { 0xFF, 0xC0, 0xCB } },
00147 { "Plum", { 0xDD, 0xA0, 0xDD } },
00148 { "PowderBlue", { 0xB0, 0xE0, 0xE6 } },
00149 { "Purple", { 0x80, 0x00, 0x80 } },
00150 { "Red", { 0xFF, 0x00, 0x00 } },
00151 { "RosyBrown", { 0xBC, 0x8F, 0x8F } },
00152 { "RoyalBlue", { 0x41, 0x69, 0xE1 } },
00153 { "SaddleBrown", { 0x8B, 0x45, 0x13 } },
00154 { "Salmon", { 0xFA, 0x80, 0x72 } },
00155 { "SandyBrown", { 0xF4, 0xA4, 0x60 } },
00156 { "SeaGreen", { 0x2E, 0x8B, 0x57 } },
00157 { "SeaShell", { 0xFF, 0xF5, 0xEE } },
00158 { "Sienna", { 0xA0, 0x52, 0x2D } },
00159 { "Silver", { 0xC0, 0xC0, 0xC0 } },
00160 { "SkyBlue", { 0x87, 0xCE, 0xEB } },
00161 { "SlateBlue", { 0x6A, 0x5A, 0xCD } },
00162 { "SlateGray", { 0x70, 0x80, 0x90 } },
00163 { "Snow", { 0xFF, 0xFA, 0xFA } },
00164 { "SpringGreen", { 0x00, 0xFF, 0x7F } },
00165 { "SteelBlue", { 0x46, 0x82, 0xB4 } },
00166 { "Tan", { 0xD2, 0xB4, 0x8C } },
00167 { "Teal", { 0x00, 0x80, 0x80 } },
00168 { "Thistle", { 0xD8, 0xBF, 0xD8 } },
00169 { "Tomato", { 0xFF, 0x63, 0x47 } },
00170 { "Turquoise", { 0x40, 0xE0, 0xD0 } },
00171 { "Violet", { 0xEE, 0x82, 0xEE } },
00172 { "Wheat", { 0xF5, 0xDE, 0xB3 } },
00173 { "White", { 0xFF, 0xFF, 0xFF } },
00174 { "WhiteSmoke", { 0xF5, 0xF5, 0xF5 } },
00175 { "Yellow", { 0xFF, 0xFF, 0x00 } },
00176 { "YellowGreen", { 0x9A, 0xCD, 0x32 } },
00177 };
00178
00179 static int color_table_compare(const void *lhs, const void *rhs)
00180 {
00181 return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
00182 }
00183
00184 #define ALPHA_SEP '@'
00185
00186 int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
00187 void *log_ctx)
00188 {
00189 char *tail, color_string2[128];
00190 const ColorEntry *entry;
00191 int len, hex_offset = 0;
00192
00193 if (color_string[0] == '#') {
00194 hex_offset = 1;
00195 } else if (!strncmp(color_string, "0x", 2))
00196 hex_offset = 2;
00197
00198 if (slen < 0)
00199 slen = strlen(color_string);
00200 av_strlcpy(color_string2, color_string + hex_offset,
00201 FFMIN(slen-hex_offset+1, sizeof(color_string2)));
00202 if ((tail = strchr(color_string2, ALPHA_SEP)))
00203 *tail++ = 0;
00204 len = strlen(color_string2);
00205 rgba_color[3] = 255;
00206
00207 if (!strcasecmp(color_string2, "random") || !strcasecmp(color_string2, "bikeshed")) {
00208 int rgba = av_get_random_seed();
00209 rgba_color[0] = rgba >> 24;
00210 rgba_color[1] = rgba >> 16;
00211 rgba_color[2] = rgba >> 8;
00212 rgba_color[3] = rgba;
00213 } else if (hex_offset ||
00214 strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
00215 char *tail;
00216 unsigned int rgba = strtoul(color_string2, &tail, 16);
00217
00218 if (*tail || (len != 6 && len != 8)) {
00219 av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
00220 return AVERROR(EINVAL);
00221 }
00222 if (len == 8) {
00223 rgba_color[3] = rgba;
00224 rgba >>= 8;
00225 }
00226 rgba_color[0] = rgba >> 16;
00227 rgba_color[1] = rgba >> 8;
00228 rgba_color[2] = rgba;
00229 } else {
00230 entry = bsearch(color_string2,
00231 color_table,
00232 FF_ARRAY_ELEMS(color_table),
00233 sizeof(ColorEntry),
00234 color_table_compare);
00235 if (!entry) {
00236 av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
00237 return AVERROR(EINVAL);
00238 }
00239 memcpy(rgba_color, entry->rgb_color, 3);
00240 }
00241
00242 if (tail) {
00243 unsigned long int alpha;
00244 const char *alpha_string = tail;
00245 if (!strncmp(alpha_string, "0x", 2)) {
00246 alpha = strtoul(alpha_string, &tail, 16);
00247 } else {
00248 alpha = 255 * strtod(alpha_string, &tail);
00249 }
00250
00251 if (tail == alpha_string || *tail || alpha > 255) {
00252 av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
00253 alpha_string, color_string);
00254 return AVERROR(EINVAL);
00255 }
00256 rgba_color[3] = alpha;
00257 }
00258
00259 return 0;
00260 }
00261
00262 #ifdef TEST
00263
00264 #undef printf
00265
00266 int main(void)
00267 {
00268 int i;
00269
00270 printf("\nTesting av_parse_color()\n");
00271 {
00272 uint8_t rgba[4];
00273 const char *color_names[] = {
00274 "bikeshed",
00275 "RaNdOm",
00276 "foo",
00277 "red",
00278 "Red ",
00279 "RED",
00280 "Violet",
00281 "Yellow",
00282 "Red",
00283 "0x000000",
00284 "0x0000000",
00285 "0xff000000",
00286 "0x3e34ff",
00287 "0x3e34ffaa",
00288 "0xffXXee",
00289 "0xfoobar",
00290 "0xffffeeeeeeee",
00291 "#ff0000",
00292 "#ffXX00",
00293 "ff0000",
00294 "ffXX00",
00295 "red@foo",
00296 "random@10",
00297 "0xff0000@1.0",
00298 "red@",
00299 "red@0xfff",
00300 "red@0xf",
00301 "red@2",
00302 "red@0.1",
00303 "red@-1",
00304 "red@0.5",
00305 "red@1.0",
00306 "red@256",
00307 "red@10foo",
00308 "red@-1.0",
00309 "red@-0.0",
00310 };
00311
00312 av_log_set_level(AV_LOG_DEBUG);
00313
00314 for (i = 0; i < FF_ARRAY_ELEMS(color_names); i++) {
00315 if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
00316 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
00317 }
00318 }
00319
00320 return 0;
00321 }
00322
00323 #endif