The R Project SVN R

Rev

Rev 70927 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*
 *  R : A Computer Language for Statistical Data Analysis
 *  Copyright (C) 1997-2014  The R Core Team
 *  Copyright (C) 2003       The R Foundation
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, a copy is available at
 *  https://www.R-project.org/Licenses/
 */

/* This should be regarded as part of the graphics engine */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <Defn.h>
#include <R_ext/GraphicsEngine.h>

#include "grDevices.h"

static char ColBuf[10];
static char HexDigits[] = "0123456789ABCDEF";

static
char *RGB2rgb(unsigned int r, unsigned int g, unsigned int b)
{
    ColBuf[0] = '#';
    ColBuf[1] = HexDigits[(r >> 4) & 15];
    ColBuf[2] = HexDigits[r & 15];
    ColBuf[3] = HexDigits[(g >> 4) & 15];
    ColBuf[4] = HexDigits[g & 15];
    ColBuf[5] = HexDigits[(b >> 4) & 15];
    ColBuf[6] = HexDigits[b & 15];
    ColBuf[7] = '\0';
    return &ColBuf[0];
}

static
char *RGBA2rgb(unsigned int r, unsigned int g, unsigned int b, unsigned int a)
{
    ColBuf[0] = '#';
    ColBuf[1] = HexDigits[(r >> 4) & 15];
    ColBuf[2] = HexDigits[r & 15];
    ColBuf[3] = HexDigits[(g >> 4) & 15];
    ColBuf[4] = HexDigits[g & 15];
    ColBuf[5] = HexDigits[(b >> 4) & 15];
    ColBuf[6] = HexDigits[b & 15];
    ColBuf[7] = HexDigits[(a >> 4) & 15];
    ColBuf[8] = HexDigits[a & 15];
    ColBuf[9] = '\0';
    return &ColBuf[0];
}


static unsigned int ScaleColor(double x)
{
    if (ISNA(x))
        error(_("color intensity %s, not in [0,1]"), "NA");
    if (!R_FINITE(x) || x < 0.0 || x > 1.0)
    error(_("color intensity %g, not in [0,1]"), x);
    return (unsigned int)(255*x + 0.5);
}

static unsigned int CheckColor(int x)
{
    if (x == NA_INTEGER)
        error(_("color intensity %s, not in 0:255"), "NA");
    if (x < 0 || x > 255)
    error(_("color intensity %d, not in 0:255"), x);
    return (unsigned int)x;
}

static unsigned int ScaleAlpha(double x)
{
    if (ISNA(x))
    error(_("alpha level %s, not in [0,1]"), "NA"); 
    if (!R_FINITE(x) || x < 0.0 || x > 1.0)
    error(_("alpha level %g, not in [0,1]"), x);
    return (unsigned int)(255*x + 0.5);
}

static unsigned int CheckAlpha(int x)
{
    if (x == NA_INTEGER)
        error(_("alpha level %s, not in 0:255"), "NA");
    if (x < 0 || x > 255)
    error(_("alpha level %d, not in 0:255"), x);
    return (unsigned int)x;
}

/* hsv2rgb -- HSV to RGB conversion  */
/* Based on HSV_TO_RGB from Foley and Van Dam First Ed. Page 616 */
/* See Alvy Ray Smith, Color Gamut Transform Pairs, SIGGRAPH '78 */

static void hsv2rgb(double h, double s, double v, 
            double *r, double *g, double *b)
{
    double f, p, q, t;
    int i;

    if (!R_FINITE(h) || !R_FINITE(s) || !R_FINITE(v)) 
    error(_("inputs must be finite")); 
    f = modf(h * 6.0, &t);
    i = ((int) t) % 6;

    p = v * (1 - s);
    q = v * (1 - s * f);
    t = v * (1 - (s * (1 - f)));
    switch (i) {
    case 0: *r = v;     *g = t;     *b = p; break;
    case 1: *r = q;     *g = v;     *b = p; break;
    case 2: *r = p;     *g = v;     *b = t; break;
    case 3: *r = p;     *g = q;     *b = v; break;
    case 4: *r = t;     *g = p;     *b = v; break;
    case 5: *r = v;     *g = p;     *b = q; break;
    default:
    error(_("bad hsv to rgb color conversion"));
    }
}

/* rgb2hsv() -- the reverse (same reference as above)
 *  this implementation is adapted from code by Nicholas Lewin-Koh.
 */
static void rgb2hsv(double r, double g, double b,
            double *h, double *s, double *v)
    /* all (r,g,b, h,s,v) values in [0,1] */
{
    double min, max, delta;
    Rboolean r_max = TRUE, b_max = FALSE;
    /* Compute  min(r,g,b) and max(r,g,b) and remember where max is: */
    min = max = r;
    if(min > g) { /* g < r */
    if(b < g)
        min = b;/* &  max = r */
    else { /* g <= b, g < r */
        min = g;
        if(b > r) { max = b; b_max = TRUE; r_max = FALSE; }
        /* else : g <= b <=r */
    }
    } else { /* r <= g */
    if(b > g) {
        max = b; b_max = TRUE; r_max = FALSE; /* &  min = r */
    } else { /* b,r <= g */
        max = g; r_max = FALSE; /* &  min = r */
        if(b < r) min = b; /* else : r <= b <= g */
    }
    }

    *v = max;
    if( max == 0 || (delta = max - min) == 0) {
    /*   r = g = b : "gray" : s = h = 0 */
    *s = *h = 0;
    return;
    }
    /* else : */
    *s = delta / max;

    if(r_max)
    *h =     ( g - b ) / delta; /* between yellow & magenta */
    else if(b_max)
    *h = 4 + ( r - g ) / delta; /* between magenta & cyan */
    else /* g == max */
    *h = 2 + ( b - r ) / delta; /* between cyan & yellow*/

    *h /= 6;
    if(*h < 0)
    *h += 1.;
    return;
}


SEXP hsv(SEXP h, SEXP s, SEXP v, SEXP a)
{
    double hh, ss, vv, aa, r=0., g=0., b=0.; /* -Wall */
    R_xlen_t i, max, nh, ns, nv, na = 1;

    PROTECT(h = coerceVector(h,REALSXP));
    PROTECT(s = coerceVector(s,REALSXP));
    PROTECT(v = coerceVector(v,REALSXP));
    if (!isNull(a)) {
    a = coerceVector(a, REALSXP);
    na = XLENGTH(a);
    }
    PROTECT(a);

    nh = XLENGTH(h);
    ns = XLENGTH(s);
    nv = XLENGTH(v);
    if (nh <= 0 || ns <= 0 || nv <= 0 || na <= 0) {
    UNPROTECT(4);
    return allocVector(STRSXP, 0);
    }
    max = nh;
    if (max < ns) max = ns;
    if (max < nv) max = nv;
    if (max < na) max = na;
    SEXP c = PROTECT(allocVector(STRSXP, max));
    if(max == 0) {
        UNPROTECT(5);
        return(c);
    }

    if(isNull(a)) {
    for (i = 0; i < max; i++) {
    hh = REAL(h)[i % nh];
    ss = REAL(s)[i % ns];
    vv = REAL(v)[i % nv];
    if (hh < 0 || hh > 1 || ss < 0 || ss > 1 || vv < 0 || vv > 1)
        error(_("invalid hsv color"));
    hsv2rgb(hh, ss, vv, &r, &g, &b);
    SET_STRING_ELT(c, i, mkChar(RGB2rgb(ScaleColor(r), ScaleColor(g),
                        ScaleColor(b))));

    }
    } else {
    for (i = 0; i < max; i++) {
    hh = REAL(h)[i % nh];
    ss = REAL(s)[i % ns];
    vv = REAL(v)[i % nv];
    aa = REAL(a)[i % na];
    if (hh < 0 || hh > 1 || ss < 0 || ss > 1 || vv < 0 || vv > 1 ||
        aa < 0 || aa > 1)
        error(_("invalid hsv color"));
    hsv2rgb(hh, ss, vv, &r, &g, &b);
    SET_STRING_ELT(c, i, mkChar(RGBA2rgb(ScaleColor(r), ScaleColor(g),
                         ScaleColor(b), ScaleAlpha(aa))));
    }
    }
    UNPROTECT(5);
    return c;
}

/* D65 White Point */

#define WHITE_X 95.047
#define WHITE_Y 100.000
#define WHITE_Z 108.883
#define WHITE_u 0.1978398
#define WHITE_v 0.4683363

/* Standard CRT Gamma */

#define GAMMA 2.4

static double gtrans(double u)
{
    if (u > 0.00304)
    return 1.055 * pow(u, (1 / GAMMA)) - 0.055;
    else
    return 12.92 * u;
}

static int FixupColor(int *r, int *g, int *b)
{
    int fix = 0;
    if (*r < 0) { *r = 0; fix = 1; } else if (*r > 255) { *r = 255; fix = 1; }
    if (*g < 0) { *g = 0; fix = 1; } else if (*g > 255) { *g = 255; fix = 1; }
    if (*b < 0) { *b = 0; fix = 1; } else if (*b > 255) { *b = 255; fix = 1; }
    return fix;
}

static void
hcl2rgb(double h, double c, double l, double *R, double *G, double *B)
{
    if (l <= 0.0) {
    *R = *G = *B = 0.0;
    return;
    }
    double L, U, V;
    double u, v;
    double X, Y, Z;

    /* Step 1 : Convert to CIE-LUV */

    h = DEG2RAD * h;
    L = l;
    U = c * cos(h);
    V = c * sin(h);

    /* Step 2 : Convert to CIE-XYZ */

    if (L <= 0 && U == 0 && V == 0) {
    X = 0; Y = 0; Z = 0;
    }
    else {
    Y = WHITE_Y * ((L > 7.999592) ? pow((L + 16)/116, 3) : L / 903.3);
    u = U / (13 * L) + WHITE_u;
    v = V / (13 * L) + WHITE_v;
    X =  9.0 * Y * u / (4 * v);
    Z =  - X / 3 - 5 * Y + 3 * Y / v;
    }

    /* Step 4 : CIE-XYZ to sRGB */

    *R = gtrans(( 3.240479 * X - 1.537150 * Y - 0.498535 * Z) / WHITE_Y);
    *G = gtrans((-0.969256 * X + 1.875992 * Y + 0.041556 * Z) / WHITE_Y);
    *B = gtrans(( 0.055648 * X - 0.204043 * Y + 1.057311 * Z) / WHITE_Y);
}

// People call this with non-finite inputs.
SEXP hcl(SEXP h, SEXP c, SEXP l, SEXP a, SEXP sfixup)
{
    double H, C, L, A, r, g, b;
    R_xlen_t nh, nc, nl, na = 1, max, i;
    int ir, ig, ib;
    int fixup;

    PROTECT(h = coerceVector(h, REALSXP));
    PROTECT(c = coerceVector(c, REALSXP));
    PROTECT(l = coerceVector(l, REALSXP));
    if (!isNull(a)) {
    a = coerceVector(a, REALSXP);
    na = XLENGTH(a);
    }
    PROTECT(a);
    fixup = asLogical(sfixup);
    nh = XLENGTH(h);
    nc = XLENGTH(c);
    nl = XLENGTH(l);
    if (nh <= 0 || nc <= 0 || nl <= 0 || na <= 0) {
    UNPROTECT(4);
    return(allocVector(STRSXP, 0));
    }
    max = nh;
    if (max < nc) max = nc;
    if (max < nl) max = nl;
    if (max < na) max = na;
    SEXP ans = PROTECT(allocVector(STRSXP, max));
    if (isNull(a)) {
    for (i = 0; i < max; i++) {
        H = REAL(h)[i % nh];
        C = REAL(c)[i % nc];
        L = REAL(l)[i % nl];
        if (R_FINITE(H) && R_FINITE(C) && R_FINITE(L)) {
        if (L < 0 || L > WHITE_Y || C < 0) error(_("invalid hcl color"));
        hcl2rgb(H, C, L, &r, &g, &b);
        ir = (int) (255 * r + .5);
        ig = (int) (255 * g + .5);
        ib = (int) (255 * b + .5);
        if (FixupColor(&ir, &ig, &ib) && !fixup)
            SET_STRING_ELT(ans, i, NA_STRING);
        else
            SET_STRING_ELT(ans, i, mkChar(RGB2rgb(ir, ig, ib)));
        } else SET_STRING_ELT(ans, i, NA_STRING);
    }
    } else {
    for (i = 0; i < max; i++) {
        H = REAL(h)[i % nh];
        C = REAL(c)[i % nc];
        L = REAL(l)[i % nl];
        A = REAL(a)[i % na];
        if (!R_FINITE(A)) A = 1;
        if (R_FINITE(H) && R_FINITE(C) && R_FINITE(L)) {
        if (L < 0 || L > WHITE_Y || C < 0 || A < 0 || A > 1)
            error(_("invalid hcl color"));
        hcl2rgb(H, C, L, &r, &g, &b);
        ir = (int) (255 * r + .5);
        ig = (int) (255 * g + .5);
        ib = (int) (255 * b + .5);
        if (FixupColor(&ir, &ig, &ib) && !fixup)
            SET_STRING_ELT(ans, i, NA_STRING);
        else
            SET_STRING_ELT(ans, i, mkChar(RGBA2rgb(ir, ig, ib,
                               ScaleAlpha(A))));
        } else SET_STRING_ELT(ans, i, NA_STRING);
    }
    }
    UNPROTECT(5);
    return ans;
}

#define _R_set_c_RGB(_R,_G,_B) \
    { for (i = 0; i < l_max; i++)  \
        SET_STRING_ELT(c, i, mkChar(RGB2rgb(_R,_G,_B))); }

#define _R_set_c_RGBA(_R,_G,_B,_A) \
    { for (i = 0; i < l_max; i++)  \
        SET_STRING_ELT(c, i, mkChar(RGBA2rgb(_R,_G,_B,_A))); }

SEXP rgb(SEXP r, SEXP g, SEXP b, SEXP a, SEXP MCV, SEXP nam)
{
    R_xlen_t i, l_max, nr, ng, nb, na = 1;
    Rboolean max_1 = FALSE;
    double mV = asReal(MCV);

    if(!R_FINITE(mV) || mV == 0.)
    error(_("invalid value of 'maxColorValue'"));
    if(mV == 255.) {
    PROTECT(r = coerceVector(r, INTSXP));
    PROTECT(g = coerceVector(g, INTSXP));
    PROTECT(b = coerceVector(b, INTSXP));
    if(!isNull(a)) a = coerceVector(a, INTSXP);
    } else {
    PROTECT(r = coerceVector(r, REALSXP));
    PROTECT(g = coerceVector(g, REALSXP));
    PROTECT(b = coerceVector(b, REALSXP));
    if(!isNull(a)) a = coerceVector(a, REALSXP);
    max_1 = (mV == 1.);
    }
    PROTECT(a);

    nr = XLENGTH(r); ng = XLENGTH(g); nb = XLENGTH(b); 
    if (!isNull(a)) na = XLENGTH(a);
    if (nr <= 0 || ng <= 0 || nb <= 0 || na <= 0) {
    UNPROTECT(4);
    return allocVector(STRSXP, 0);
    }
    l_max = nr;
    if (l_max < ng) l_max = ng;
    if (l_max < nb) l_max = nb;
    if (l_max < na) l_max = na;

    PROTECT(nam = coerceVector(nam, STRSXP));
    if (length(nam) != 0 && length(nam) != l_max)
    error(_("invalid 'names' vector"));
    SEXP c = PROTECT(allocVector(STRSXP, l_max));

    if(mV == 255.0) {
    if(isNull(a)) {
        _R_set_c_RGB(CheckColor(INTEGER(r)[i%nr]),
              CheckColor(INTEGER(g)[i%ng]),
              CheckColor(INTEGER(b)[i%nb]));
    } else {
        _R_set_c_RGBA(CheckColor(INTEGER(r)[i%nr]),
              CheckColor(INTEGER(g)[i%ng]),
              CheckColor(INTEGER(b)[i%nb]),
              CheckAlpha(INTEGER(a)[i%na]));
    }
    }
    else if(max_1) {
    if(isNull(a)) {
        _R_set_c_RGB(ScaleColor(REAL(r)[i%nr]),
             ScaleColor(REAL(g)[i%ng]),
             ScaleColor(REAL(b)[i%nb]));
    } else {
        _R_set_c_RGBA(ScaleColor(REAL(r)[i%nr]),
              ScaleColor(REAL(g)[i%ng]),
              ScaleColor(REAL(b)[i%nb]),
              ScaleAlpha(REAL(a)[i%na]));
    }
    }
    else { /* maxColorVal not in {1, 255} */
    if(isNull(a)) {
        _R_set_c_RGB(ScaleColor(REAL(r)[i%nr] / mV),
             ScaleColor(REAL(g)[i%ng] / mV),
             ScaleColor(REAL(b)[i%nb] / mV));
    } else {
        _R_set_c_RGBA(ScaleColor(REAL(r)[i%nr] / mV),
              ScaleColor(REAL(g)[i%ng] / mV),
              ScaleColor(REAL(b)[i%nb] / mV),
              ScaleAlpha(REAL(a)[i%na] / mV));
    }
    }
    if (length(nam) != 0) setAttrib(c, R_NamesSymbol, nam);
    UNPROTECT(6);
    return c;
}

SEXP gray(SEXP lev, SEXP a)
{
    SEXP ans;
    double level;
    int i, ilevel, nlev;

    lev  = PROTECT(coerceVector(lev,REALSXP));
    if(!isNull(a)) a = coerceVector(a,REALSXP);
    PROTECT(a);
    nlev = LENGTH(lev);
    PROTECT(ans = allocVector(STRSXP, nlev));
    if(isNull(a)) {
    for (i = 0; i < nlev; i++) {
        level = REAL(lev)[i];
        if (ISNAN(level) || level < 0 || level > 1)
        error(_("invalid gray level, must be in [0,1]."));
        ilevel = (int)(255 * level + 0.5);
        SET_STRING_ELT(ans, i, mkChar(RGB2rgb(ilevel, ilevel, ilevel)));
    }
    } else {
    int na = length(a);
    for (i = 0; i < (nlev > na ? nlev : na); i++) {
        level = REAL(lev)[i % nlev];
        if (ISNAN(level) || level < 0 || level > 1)
        error(_("invalid gray level, must be in [0,1]."));
        ilevel = (int)(255 * level + 0.5);
        double aa = REAL(a)[i % na];
        SET_STRING_ELT(ans, i, mkChar(RGBA2rgb(ilevel, ilevel, ilevel,
                           ScaleAlpha(aa))));
    }
    }
    UNPROTECT(3);
    return ans;
}





SEXP RGB2hsv(SEXP rgb)
{
/* (r,g,b) -> (h,s,v) conversion */
    SEXP dd, ans, names, dmns;
    int n, i, i3;

    rgb = PROTECT(coerceVector(rgb, REALSXP));
    if(!isMatrix(rgb)) error("rgb is not a matrix (internally)");
    dd = getAttrib(rgb, R_DimSymbol);
    if(INTEGER(dd)[0] != 3) error("rgb must have 3 rows (internally)");
    n = INTEGER(dd)[1];

    ans = PROTECT(allocMatrix(REALSXP, 3, n));
    PROTECT(dmns = allocVector(VECSXP, 2));
    /* row names: */
    PROTECT(names = allocVector(STRSXP, 3));
    SET_STRING_ELT(names, 0, mkChar("h"));
    SET_STRING_ELT(names, 1, mkChar("s"));
    SET_STRING_ELT(names, 2, mkChar("v"));
    SET_VECTOR_ELT(dmns, 0, names);
    /* column names if input has: */
    if ((dd = getAttrib(rgb, R_DimNamesSymbol)) != R_NilValue &&
    (names = VECTOR_ELT(dd, 1)) != R_NilValue)
    SET_VECTOR_ELT(dmns, 1, names);
    setAttrib(ans, R_DimNamesSymbol, dmns);
    UNPROTECT(2);/* names, dmns */

    for(i = i3 = 0; i < n; i++, i3 += 3) {
    rgb2hsv(REAL(rgb)[i3+ 0],  REAL(rgb)[i3+ 1],  REAL(rgb)[i3+ 2],
        &REAL(ans)[i3+ 0], &REAL(ans)[i3+ 1], &REAL(ans)[i3 +2]);
    }
    UNPROTECT(2);
    return ans;
}


SEXP col2rgb(SEXP colors, SEXP alpha)
{
    SEXP ans, names, dmns;

    int alph = asLogical(alpha);
    if(alph == NA_LOGICAL) error(_("invalid '%s' value"), "alpha");
    switch(TYPEOF(colors)) {
    case INTSXP:
    case STRSXP:
    break;
    case REALSXP:
    colors = coerceVector(colors, INTSXP);
    break;
    default:
    colors = coerceVector(colors, STRSXP);
    break;
    }
    PROTECT(colors);
    int n = LENGTH(colors);

    /* First set up the output matrix */
    PROTECT(ans = allocMatrix(INTSXP, 3+alph, n));
    PROTECT(dmns = allocVector(VECSXP, 2));
    PROTECT(names = allocVector(STRSXP, 3+alph));
    SET_STRING_ELT(names, 0, mkChar("red"));
    SET_STRING_ELT(names, 1, mkChar("green"));
    SET_STRING_ELT(names, 2, mkChar("blue"));
    if(alph) SET_STRING_ELT(names, 3, mkChar("alpha"));
    SET_VECTOR_ELT(dmns, 0, names);
    if ((names = getAttrib(colors, R_NamesSymbol)) != R_NilValue)
    SET_VECTOR_ELT(dmns, 1, names);
    setAttrib(ans, R_DimNamesSymbol, dmns);

    for(int i = 0, j = 0; i < n; i++) {
    rcolor icol = inRGBpar3(colors, i, R_TRANWHITE);
    INTEGER(ans)[j++] = R_RED(icol);
    INTEGER(ans)[j++] = R_GREEN(icol);
    INTEGER(ans)[j++] = R_BLUE(icol);
    if(alph) INTEGER(ans)[j++] = R_ALPHA(icol);
    }
    UNPROTECT(4);
    return ans;
}


// ------------------ code for tables to export to main executable --------

#include <ctype.h> /* for tolower, isdigit */

#define MAX_PALETTE_SIZE 1024
static int PaletteSize = 8;
static rcolor Palette[MAX_PALETTE_SIZE] = {
    0xff000000,
    0xff0000ff,
    0xff00cd00,
    0xffff0000,
    0xffffff00,
    0xffff00ff,
    0xff00ffff,
    0xffbebebe
};

static rcolor Palette0[MAX_PALETTE_SIZE];


/* String comparison ignoring case and squeezing out blanks */
static int StrMatch(const char *s, const char *t)
{
    for(;;) {
    if(*s == '\0' && *t == '\0') return 1;
    if(*s == ' ') { s++; continue; }
    if(*t == ' ') { t++; continue; }
    if(tolower(*s++) != tolower(*t++)) return 0;
    }
}


/*
 *  Color Specification
 *
 *  Colors are stored internally in integers.  Each integer is
 *  broken into four bytes.  The three least significant bytes
 *  are used to contain levels of red, green and blue.  These
 *  levels are integers in the range [0,255].
 *
 *  Externally, colors are specified either:
 *
 *    a) by name, using a large table of color names,
 *
 *    b) by RGB values using a string of the form "#rrggbb"
 *   where rr, gg and bb are hex integers giving the level
 *   of red green and blue,
 *
 *    c) as an index into a user setable palette of colors.
 *
 */

/* Default Color Palette */
/* Paul Murrell 05/06/02 (2002, probably)
 * Changed "white" to "grey" in the default palette
 * in response to user suggestion
 */
attribute_hidden
const char *DefaultPalette[] = {
    "black",
    "red",
    "green3",
    "blue",
    "cyan",
    "magenta",
    "yellow",
    "grey",
    NULL
};

/* The Table of Known Color Names */
/* Adapted from the X11 RGB database */
/* Note: the color "white" was moved to the top of the database 
   to avoid its being looked up by col2name as "gray100" */

typedef
struct colorDataBaseEntry {
    char *name;   // X11 Color Name
    char *rgb;    // #RRGGBB String, no longer used
    rcolor code;  // Internal R Color Code
} ColorDataBaseEntry;

static ColorDataBaseEntry ColorDataBase[] = {
    /* name     rgb         code */
    {"white",   "#FFFFFF",   0xffffffff},
    {"aliceblue",   "#F0F8FF",   0xfffff8f0},
    {"antiquewhite",    "#FAEBD7",   0xffd7ebfa},
    {"antiquewhite1",   "#FFEFDB",   0xffdbefff},
    {"antiquewhite2",   "#EEDFCC",   0xffccdfee},
    {"antiquewhite3",   "#CDC0B0",   0xffb0c0cd},
    {"antiquewhite4",   "#8B8378",   0xff78838b},
    {"aquamarine",  "#7FFFD4",   0xffd4ff7f},
    {"aquamarine1", "#7FFFD4",   0xffd4ff7f},
    {"aquamarine2", "#76EEC6",   0xffc6ee76},
    {"aquamarine3", "#66CDAA",   0xffaacd66},
    {"aquamarine4", "#458B74",   0xff748b45},
    {"azure",   "#F0FFFF",   0xfffffff0},
    {"azure1",  "#F0FFFF",   0xfffffff0},
    {"azure2",  "#E0EEEE",   0xffeeeee0},
    {"azure3",  "#C1CDCD",   0xffcdcdc1},
    {"azure4",  "#838B8B",   0xff8b8b83},
    {"beige",   "#F5F5DC",   0xffdcf5f5},
    {"bisque",  "#FFE4C4",   0xffc4e4ff},
    {"bisque1", "#FFE4C4",   0xffc4e4ff},
    {"bisque2", "#EED5B7",   0xffb7d5ee},
    {"bisque3", "#CDB79E",   0xff9eb7cd},
    {"bisque4", "#8B7D6B",   0xff6b7d8b},
    {"black",   "#000000",   0xff000000},
    {"blanchedalmond",  "#FFEBCD",   0xffcdebff},
    {"blue",    "#0000FF",   0xffff0000},
    {"blue1",   "#0000FF",   0xffff0000},
    {"blue2",   "#0000EE",   0xffee0000},
    {"blue3",   "#0000CD",   0xffcd0000},
    {"blue4",   "#00008B",   0xff8b0000},
    {"blueviolet",  "#8A2BE2",   0xffe22b8a},
    {"brown",   "#A52A2A",   0xff2a2aa5},
    {"brown1",  "#FF4040",   0xff4040ff},
    {"brown2",  "#EE3B3B",   0xff3b3bee},
    {"brown3",  "#CD3333",   0xff3333cd},
    {"brown4",  "#8B2323",   0xff23238b},
    {"burlywood",   "#DEB887",   0xff87b8de},
    {"burlywood1",  "#FFD39B",   0xff9bd3ff},
    {"burlywood2",  "#EEC591",   0xff91c5ee},
    {"burlywood3",  "#CDAA7D",   0xff7daacd},
    {"burlywood4",  "#8B7355",   0xff55738b},
    {"cadetblue",   "#5F9EA0",   0xffa09e5f},
    {"cadetblue1",  "#98F5FF",   0xfffff598},
    {"cadetblue2",  "#8EE5EE",   0xffeee58e},
    {"cadetblue3",  "#7AC5CD",   0xffcdc57a},
    {"cadetblue4",  "#53868B",   0xff8b8653},
    {"chartreuse",  "#7FFF00",   0xff00ff7f},
    {"chartreuse1", "#7FFF00",   0xff00ff7f},
    {"chartreuse2", "#76EE00",   0xff00ee76},
    {"chartreuse3", "#66CD00",   0xff00cd66},
    {"chartreuse4", "#458B00",   0xff008b45},
    {"chocolate",   "#D2691E",   0xff1e69d2},
    {"chocolate1",  "#FF7F24",   0xff247fff},
    {"chocolate2",  "#EE7621",   0xff2176ee},
    {"chocolate3",  "#CD661D",   0xff1d66cd},
    {"chocolate4",  "#8B4513",   0xff13458b},
    {"coral",   "#FF7F50",   0xff507fff},
    {"coral1",  "#FF7256",   0xff5672ff},
    {"coral2",  "#EE6A50",   0xff506aee},
    {"coral3",  "#CD5B45",   0xff455bcd},
    {"coral4",  "#8B3E2F",   0xff2f3e8b},
    {"cornflowerblue",  "#6495ED",   0xffed9564},
    {"cornsilk",    "#FFF8DC",   0xffdcf8ff},
    {"cornsilk1",   "#FFF8DC",   0xffdcf8ff},
    {"cornsilk2",   "#EEE8CD",   0xffcde8ee},
    {"cornsilk3",   "#CDC8B1",   0xffb1c8cd},
    {"cornsilk4",   "#8B8878",   0xff78888b},
    {"cyan",    "#00FFFF",   0xffffff00},
    {"cyan1",   "#00FFFF",   0xffffff00},
    {"cyan2",   "#00EEEE",   0xffeeee00},
    {"cyan3",   "#00CDCD",   0xffcdcd00},
    {"cyan4",   "#008B8B",   0xff8b8b00},
    {"darkblue",    "#00008B",   0xff8b0000},
    {"darkcyan",    "#008B8B",   0xff8b8b00},
    {"darkgoldenrod",   "#B8860B",   0xff0b86b8},
    {"darkgoldenrod1",  "#FFB90F",   0xff0fb9ff},
    {"darkgoldenrod2",  "#EEAD0E",   0xff0eadee},
    {"darkgoldenrod3",  "#CD950C",   0xff0c95cd},
    {"darkgoldenrod4",  "#8B6508",   0xff08658b},
    {"darkgray",    "#A9A9A9",   0xffa9a9a9},
    {"darkgreen",   "#006400",   0xff006400},
    {"darkgrey",    "#A9A9A9",   0xffa9a9a9},
    {"darkkhaki",   "#BDB76B",   0xff6bb7bd},
    {"darkmagenta", "#8B008B",   0xff8b008b},
    {"darkolivegreen",  "#556B2F",   0xff2f6b55},
    {"darkolivegreen1", "#CAFF70",   0xff70ffca},
    {"darkolivegreen2", "#BCEE68",   0xff68eebc},
    {"darkolivegreen3", "#A2CD5A",   0xff5acda2},
    {"darkolivegreen4", "#6E8B3D",   0xff3d8b6e},
    {"darkorange",  "#FF8C00",   0xff008cff},
    {"darkorange1", "#FF7F00",   0xff007fff},
    {"darkorange2", "#EE7600",   0xff0076ee},
    {"darkorange3", "#CD6600",   0xff0066cd},
    {"darkorange4", "#8B4500",   0xff00458b},
    {"darkorchid",  "#9932CC",   0xffcc3299},
    {"darkorchid1", "#BF3EFF",   0xffff3ebf},
    {"darkorchid2", "#B23AEE",   0xffee3ab2},
    {"darkorchid3", "#9A32CD",   0xffcd329a},
    {"darkorchid4", "#68228B",   0xff8b2268},
    {"darkred", "#8B0000",   0xff00008b},
    {"darksalmon",  "#E9967A",   0xff7a96e9},
    {"darkseagreen",    "#8FBC8F",   0xff8fbc8f},
    {"darkseagreen1",   "#C1FFC1",   0xffc1ffc1},
    {"darkseagreen2",   "#B4EEB4",   0xffb4eeb4},
    {"darkseagreen3",   "#9BCD9B",   0xff9bcd9b},
    {"darkseagreen4",   "#698B69",   0xff698b69},
    {"darkslateblue",   "#483D8B",   0xff8b3d48},
    {"darkslategray",   "#2F4F4F",   0xff4f4f2f},
    {"darkslategray1",  "#97FFFF",   0xffffff97},
    {"darkslategray2",  "#8DEEEE",   0xffeeee8d},
    {"darkslategray3",  "#79CDCD",   0xffcdcd79},
    {"darkslategray4",  "#528B8B",   0xff8b8b52},
    {"darkslategrey",   "#2F4F4F",   0xff4f4f2f},
    {"darkturquoise",   "#00CED1",   0xffd1ce00},
    {"darkviolet",  "#9400D3",   0xffd30094},
    {"deeppink",    "#FF1493",   0xff9314ff},
    {"deeppink1",   "#FF1493",   0xff9314ff},
    {"deeppink2",   "#EE1289",   0xff8912ee},
    {"deeppink3",   "#CD1076",   0xff7610cd},
    {"deeppink4",   "#8B0A50",   0xff500a8b},
    {"deepskyblue", "#00BFFF",   0xffffbf00},
    {"deepskyblue1",    "#00BFFF",   0xffffbf00},
    {"deepskyblue2",    "#00B2EE",   0xffeeb200},
    {"deepskyblue3",    "#009ACD",   0xffcd9a00},
    {"deepskyblue4",    "#00688B",   0xff8b6800},
    {"dimgray", "#696969",   0xff696969},
    {"dimgrey", "#696969",   0xff696969},
    {"dodgerblue",  "#1E90FF",   0xffff901e},
    {"dodgerblue1", "#1E90FF",   0xffff901e},
    {"dodgerblue2", "#1C86EE",   0xffee861c},
    {"dodgerblue3", "#1874CD",   0xffcd7418},
    {"dodgerblue4", "#104E8B",   0xff8b4e10},
    {"firebrick",   "#B22222",   0xff2222b2},
    {"firebrick1",  "#FF3030",   0xff3030ff},
    {"firebrick2",  "#EE2C2C",   0xff2c2cee},
    {"firebrick3",  "#CD2626",   0xff2626cd},
    {"firebrick4",  "#8B1A1A",   0xff1a1a8b},
    {"floralwhite", "#FFFAF0",   0xfff0faff},
    {"forestgreen", "#228B22",   0xff228b22},
    {"gainsboro",   "#DCDCDC",   0xffdcdcdc},
    {"ghostwhite",  "#F8F8FF",   0xfffff8f8},
    {"gold",    "#FFD700",   0xff00d7ff},
    {"gold1",   "#FFD700",   0xff00d7ff},
    {"gold2",   "#EEC900",   0xff00c9ee},
    {"gold3",   "#CDAD00",   0xff00adcd},
    {"gold4",   "#8B7500",   0xff00758b},
    {"goldenrod",   "#DAA520",   0xff20a5da},
    {"goldenrod1",  "#FFC125",   0xff25c1ff},
    {"goldenrod2",  "#EEB422",   0xff22b4ee},
    {"goldenrod3",  "#CD9B1D",   0xff1d9bcd},
    {"goldenrod4",  "#8B6914",   0xff14698b},
    {"gray",    "#BEBEBE",   0xffbebebe},
    {"gray0",   "#000000",   0xff000000},
    {"gray1",   "#030303",   0xff030303},
    {"gray2",   "#050505",   0xff050505},
    {"gray3",   "#080808",   0xff080808},
    {"gray4",   "#0A0A0A",   0xff0a0a0a},
    {"gray5",   "#0D0D0D",   0xff0d0d0d},
    {"gray6",   "#0F0F0F",   0xff0f0f0f},
    {"gray7",   "#121212",   0xff121212},
    {"gray8",   "#141414",   0xff141414},
    {"gray9",   "#171717",   0xff171717},
    {"gray10",  "#1A1A1A",   0xff1a1a1a},
    {"gray11",  "#1C1C1C",   0xff1c1c1c},
    {"gray12",  "#1F1F1F",   0xff1f1f1f},
    {"gray13",  "#212121",   0xff212121},
    {"gray14",  "#242424",   0xff242424},
    {"gray15",  "#262626",   0xff262626},
    {"gray16",  "#292929",   0xff292929},
    {"gray17",  "#2B2B2B",   0xff2b2b2b},
    {"gray18",  "#2E2E2E",   0xff2e2e2e},
    {"gray19",  "#303030",   0xff303030},
    {"gray20",  "#333333",   0xff333333},
    {"gray21",  "#363636",   0xff363636},
    {"gray22",  "#383838",   0xff383838},
    {"gray23",  "#3B3B3B",   0xff3b3b3b},
    {"gray24",  "#3D3D3D",   0xff3d3d3d},
    {"gray25",  "#404040",   0xff404040},
    {"gray26",  "#424242",   0xff424242},
    {"gray27",  "#454545",   0xff454545},
    {"gray28",  "#474747",   0xff474747},
    {"gray29",  "#4A4A4A",   0xff4a4a4a},
    {"gray30",  "#4D4D4D",   0xff4d4d4d},
    {"gray31",  "#4F4F4F",   0xff4f4f4f},
    {"gray32",  "#525252",   0xff525252},
    {"gray33",  "#545454",   0xff545454},
    {"gray34",  "#575757",   0xff575757},
    {"gray35",  "#595959",   0xff595959},
    {"gray36",  "#5C5C5C",   0xff5c5c5c},
    {"gray37",  "#5E5E5E",   0xff5e5e5e},
    {"gray38",  "#616161",   0xff616161},
    {"gray39",  "#636363",   0xff636363},
    {"gray40",  "#666666",   0xff666666},
    {"gray41",  "#696969",   0xff696969},
    {"gray42",  "#6B6B6B",   0xff6b6b6b},
    {"gray43",  "#6E6E6E",   0xff6e6e6e},
    {"gray44",  "#707070",   0xff707070},
    {"gray45",  "#737373",   0xff737373},
    {"gray46",  "#757575",   0xff757575},
    {"gray47",  "#787878",   0xff787878},
    {"gray48",  "#7A7A7A",   0xff7a7a7a},
    {"gray49",  "#7D7D7D",   0xff7d7d7d},
    {"gray50",  "#7F7F7F",   0xff7f7f7f},
    {"gray51",  "#828282",   0xff828282},
    {"gray52",  "#858585",   0xff858585},
    {"gray53",  "#878787",   0xff878787},
    {"gray54",  "#8A8A8A",   0xff8a8a8a},
    {"gray55",  "#8C8C8C",   0xff8c8c8c},
    {"gray56",  "#8F8F8F",   0xff8f8f8f},
    {"gray57",  "#919191",   0xff919191},
    {"gray58",  "#949494",   0xff949494},
    {"gray59",  "#969696",   0xff969696},
    {"gray60",  "#999999",   0xff999999},
    {"gray61",  "#9C9C9C",   0xff9c9c9c},
    {"gray62",  "#9E9E9E",   0xff9e9e9e},
    {"gray63",  "#A1A1A1",   0xffa1a1a1},
    {"gray64",  "#A3A3A3",   0xffa3a3a3},
    {"gray65",  "#A6A6A6",   0xffa6a6a6},
    {"gray66",  "#A8A8A8",   0xffa8a8a8},
    {"gray67",  "#ABABAB",   0xffababab},
    {"gray68",  "#ADADAD",   0xffadadad},
    {"gray69",  "#B0B0B0",   0xffb0b0b0},
    {"gray70",  "#B3B3B3",   0xffb3b3b3},
    {"gray71",  "#B5B5B5",   0xffb5b5b5},
    {"gray72",  "#B8B8B8",   0xffb8b8b8},
    {"gray73",  "#BABABA",   0xffbababa},
    {"gray74",  "#BDBDBD",   0xffbdbdbd},
    {"gray75",  "#BFBFBF",   0xffbfbfbf},
    {"gray76",  "#C2C2C2",   0xffc2c2c2},
    {"gray77",  "#C4C4C4",   0xffc4c4c4},
    {"gray78",  "#C7C7C7",   0xffc7c7c7},
    {"gray79",  "#C9C9C9",   0xffc9c9c9},
    {"gray80",  "#CCCCCC",   0xffcccccc},
    {"gray81",  "#CFCFCF",   0xffcfcfcf},
    {"gray82",  "#D1D1D1",   0xffd1d1d1},
    {"gray83",  "#D4D4D4",   0xffd4d4d4},
    {"gray84",  "#D6D6D6",   0xffd6d6d6},
    {"gray85",  "#D9D9D9",   0xffd9d9d9},
    {"gray86",  "#DBDBDB",   0xffdbdbdb},
    {"gray87",  "#DEDEDE",   0xffdedede},
    {"gray88",  "#E0E0E0",   0xffe0e0e0},
    {"gray89",  "#E3E3E3",   0xffe3e3e3},
    {"gray90",  "#E5E5E5",   0xffe5e5e5},
    {"gray91",  "#E8E8E8",   0xffe8e8e8},
    {"gray92",  "#EBEBEB",   0xffebebeb},
    {"gray93",  "#EDEDED",   0xffededed},
    {"gray94",  "#F0F0F0",   0xfff0f0f0},
    {"gray95",  "#F2F2F2",   0xfff2f2f2},
    {"gray96",  "#F5F5F5",   0xfff5f5f5},
    {"gray97",  "#F7F7F7",   0xfff7f7f7},
    {"gray98",  "#FAFAFA",   0xfffafafa},
    {"gray99",  "#FCFCFC",   0xfffcfcfc},
    {"gray100", "#FFFFFF",   0xffffffff},
    {"green",   "#00FF00",   0xff00ff00},
    {"green1",  "#00FF00",   0xff00ff00},
    {"green2",  "#00EE00",   0xff00ee00},
    {"green3",  "#00CD00",   0xff00cd00},
    {"green4",  "#008B00",   0xff008b00},
    {"greenyellow", "#ADFF2F",   0xff2fffad},
    {"grey",    "#BEBEBE",   0xffbebebe},
    {"grey0",   "#000000",   0xff000000},
    {"grey1",   "#030303",   0xff030303},
    {"grey2",   "#050505",   0xff050505},
    {"grey3",   "#080808",   0xff080808},
    {"grey4",   "#0A0A0A",   0xff0a0a0a},
    {"grey5",   "#0D0D0D",   0xff0d0d0d},
    {"grey6",   "#0F0F0F",   0xff0f0f0f},
    {"grey7",   "#121212",   0xff121212},
    {"grey8",   "#141414",   0xff141414},
    {"grey9",   "#171717",   0xff171717},
    {"grey10",  "#1A1A1A",   0xff1a1a1a},
    {"grey11",  "#1C1C1C",   0xff1c1c1c},
    {"grey12",  "#1F1F1F",   0xff1f1f1f},
    {"grey13",  "#212121",   0xff212121},
    {"grey14",  "#242424",   0xff242424},
    {"grey15",  "#262626",   0xff262626},
    {"grey16",  "#292929",   0xff292929},
    {"grey17",  "#2B2B2B",   0xff2b2b2b},
    {"grey18",  "#2E2E2E",   0xff2e2e2e},
    {"grey19",  "#303030",   0xff303030},
    {"grey20",  "#333333",   0xff333333},
    {"grey21",  "#363636",   0xff363636},
    {"grey22",  "#383838",   0xff383838},
    {"grey23",  "#3B3B3B",   0xff3b3b3b},
    {"grey24",  "#3D3D3D",   0xff3d3d3d},
    {"grey25",  "#404040",   0xff404040},
    {"grey26",  "#424242",   0xff424242},
    {"grey27",  "#454545",   0xff454545},
    {"grey28",  "#474747",   0xff474747},
    {"grey29",  "#4A4A4A",   0xff4a4a4a},
    {"grey30",  "#4D4D4D",   0xff4d4d4d},
    {"grey31",  "#4F4F4F",   0xff4f4f4f},
    {"grey32",  "#525252",   0xff525252},
    {"grey33",  "#545454",   0xff545454},
    {"grey34",  "#575757",   0xff575757},
    {"grey35",  "#595959",   0xff595959},
    {"grey36",  "#5C5C5C",   0xff5c5c5c},
    {"grey37",  "#5E5E5E",   0xff5e5e5e},
    {"grey38",  "#616161",   0xff616161},
    {"grey39",  "#636363",   0xff636363},
    {"grey40",  "#666666",   0xff666666},
    {"grey41",  "#696969",   0xff696969},
    {"grey42",  "#6B6B6B",   0xff6b6b6b},
    {"grey43",  "#6E6E6E",   0xff6e6e6e},
    {"grey44",  "#707070",   0xff707070},
    {"grey45",  "#737373",   0xff737373},
    {"grey46",  "#757575",   0xff757575},
    {"grey47",  "#787878",   0xff787878},
    {"grey48",  "#7A7A7A",   0xff7a7a7a},
    {"grey49",  "#7D7D7D",   0xff7d7d7d},
    {"grey50",  "#7F7F7F",   0xff7f7f7f},
    {"grey51",  "#828282",   0xff828282},
    {"grey52",  "#858585",   0xff858585},
    {"grey53",  "#878787",   0xff878787},
    {"grey54",  "#8A8A8A",   0xff8a8a8a},
    {"grey55",  "#8C8C8C",   0xff8c8c8c},
    {"grey56",  "#8F8F8F",   0xff8f8f8f},
    {"grey57",  "#919191",   0xff919191},
    {"grey58",  "#949494",   0xff949494},
    {"grey59",  "#969696",   0xff969696},
    {"grey60",  "#999999",   0xff999999},
    {"grey61",  "#9C9C9C",   0xff9c9c9c},
    {"grey62",  "#9E9E9E",   0xff9e9e9e},
    {"grey63",  "#A1A1A1",   0xffa1a1a1},
    {"grey64",  "#A3A3A3",   0xffa3a3a3},
    {"grey65",  "#A6A6A6",   0xffa6a6a6},
    {"grey66",  "#A8A8A8",   0xffa8a8a8},
    {"grey67",  "#ABABAB",   0xffababab},
    {"grey68",  "#ADADAD",   0xffadadad},
    {"grey69",  "#B0B0B0",   0xffb0b0b0},
    {"grey70",  "#B3B3B3",   0xffb3b3b3},
    {"grey71",  "#B5B5B5",   0xffb5b5b5},
    {"grey72",  "#B8B8B8",   0xffb8b8b8},
    {"grey73",  "#BABABA",   0xffbababa},
    {"grey74",  "#BDBDBD",   0xffbdbdbd},
    {"grey75",  "#BFBFBF",   0xffbfbfbf},
    {"grey76",  "#C2C2C2",   0xffc2c2c2},
    {"grey77",  "#C4C4C4",   0xffc4c4c4},
    {"grey78",  "#C7C7C7",   0xffc7c7c7},
    {"grey79",  "#C9C9C9",   0xffc9c9c9},
    {"grey80",  "#CCCCCC",   0xffcccccc},
    {"grey81",  "#CFCFCF",   0xffcfcfcf},
    {"grey82",  "#D1D1D1",   0xffd1d1d1},
    {"grey83",  "#D4D4D4",   0xffd4d4d4},
    {"grey84",  "#D6D6D6",   0xffd6d6d6},
    {"grey85",  "#D9D9D9",   0xffd9d9d9},
    {"grey86",  "#DBDBDB",   0xffdbdbdb},
    {"grey87",  "#DEDEDE",   0xffdedede},
    {"grey88",  "#E0E0E0",   0xffe0e0e0},
    {"grey89",  "#E3E3E3",   0xffe3e3e3},
    {"grey90",  "#E5E5E5",   0xffe5e5e5},
    {"grey91",  "#E8E8E8",   0xffe8e8e8},
    {"grey92",  "#EBEBEB",   0xffebebeb},
    {"grey93",  "#EDEDED",   0xffededed},
    {"grey94",  "#F0F0F0",   0xfff0f0f0},
    {"grey95",  "#F2F2F2",   0xfff2f2f2},
    {"grey96",  "#F5F5F5",   0xfff5f5f5},
    {"grey97",  "#F7F7F7",   0xfff7f7f7},
    {"grey98",  "#FAFAFA",   0xfffafafa},
    {"grey99",  "#FCFCFC",   0xfffcfcfc},
    {"grey100", "#FFFFFF",   0xffffffff},
    {"honeydew",    "#F0FFF0",   0xfff0fff0},
    {"honeydew1",   "#F0FFF0",   0xfff0fff0},
    {"honeydew2",   "#E0EEE0",   0xffe0eee0},
    {"honeydew3",   "#C1CDC1",   0xffc1cdc1},
    {"honeydew4",   "#838B83",   0xff838b83},
    {"hotpink", "#FF69B4",   0xffb469ff},
    {"hotpink1",    "#FF6EB4",   0xffb46eff},
    {"hotpink2",    "#EE6AA7",   0xffa76aee},
    {"hotpink3",    "#CD6090",   0xff9060cd},
    {"hotpink4",    "#8B3A62",   0xff623a8b},
    {"indianred",   "#CD5C5C",   0xff5c5ccd},
    {"indianred1",  "#FF6A6A",   0xff6a6aff},
    {"indianred2",  "#EE6363",   0xff6363ee},
    {"indianred3",  "#CD5555",   0xff5555cd},
    {"indianred4",  "#8B3A3A",   0xff3a3a8b},
    {"ivory",   "#FFFFF0",   0xfff0ffff},
    {"ivory1",  "#FFFFF0",   0xfff0ffff},
    {"ivory2",  "#EEEEE0",   0xffe0eeee},
    {"ivory3",  "#CDCDC1",   0xffc1cdcd},
    {"ivory4",  "#8B8B83",   0xff838b8b},
    {"khaki",   "#F0E68C",   0xff8ce6f0},
    {"khaki1",  "#FFF68F",   0xff8ff6ff},
    {"khaki2",  "#EEE685",   0xff85e6ee},
    {"khaki3",  "#CDC673",   0xff73c6cd},
    {"khaki4",  "#8B864E",   0xff4e868b},
    {"lavender",    "#E6E6FA",   0xfffae6e6},
    {"lavenderblush",   "#FFF0F5",   0xfff5f0ff},
    {"lavenderblush1",  "#FFF0F5",   0xfff5f0ff},
    {"lavenderblush2",  "#EEE0E5",   0xffe5e0ee},
    {"lavenderblush3",  "#CDC1C5",   0xffc5c1cd},
    {"lavenderblush4",  "#8B8386",   0xff86838b},
    {"lawngreen",   "#7CFC00",   0xff00fc7c},
    {"lemonchiffon",    "#FFFACD",   0xffcdfaff},
    {"lemonchiffon1",   "#FFFACD",   0xffcdfaff},
    {"lemonchiffon2",   "#EEE9BF",   0xffbfe9ee},
    {"lemonchiffon3",   "#CDC9A5",   0xffa5c9cd},
    {"lemonchiffon4",   "#8B8970",   0xff70898b},
    {"lightblue",   "#ADD8E6",   0xffe6d8ad},
    {"lightblue1",  "#BFEFFF",   0xffffefbf},
    {"lightblue2",  "#B2DFEE",   0xffeedfb2},
    {"lightblue3",  "#9AC0CD",   0xffcdc09a},
    {"lightblue4",  "#68838B",   0xff8b8368},
    {"lightcoral",  "#F08080",   0xff8080f0},
    {"lightcyan",   "#E0FFFF",   0xffffffe0},
    {"lightcyan1",  "#E0FFFF",   0xffffffe0},
    {"lightcyan2",  "#D1EEEE",   0xffeeeed1},
    {"lightcyan3",  "#B4CDCD",   0xffcdcdb4},
    {"lightcyan4",  "#7A8B8B",   0xff8b8b7a},
    {"lightgoldenrod",  "#EEDD82",   0xff82ddee},
    {"lightgoldenrod1", "#FFEC8B",   0xff8becff},
    {"lightgoldenrod2", "#EEDC82",   0xff82dcee},
    {"lightgoldenrod3", "#CDBE70",   0xff70becd},
    {"lightgoldenrod4", "#8B814C",   0xff4c818b},
    {"lightgoldenrodyellow",    "#FAFAD2",   0xffd2fafa},
    {"lightgray",   "#D3D3D3",   0xffd3d3d3},
    {"lightgreen",  "#90EE90",   0xff90ee90},
    {"lightgrey",   "#D3D3D3",   0xffd3d3d3},
    {"lightpink",   "#FFB6C1",   0xffc1b6ff},
    {"lightpink1",  "#FFAEB9",   0xffb9aeff},
    {"lightpink2",  "#EEA2AD",   0xffada2ee},
    {"lightpink3",  "#CD8C95",   0xff958ccd},
    {"lightpink4",  "#8B5F65",   0xff655f8b},
    {"lightsalmon", "#FFA07A",   0xff7aa0ff},
    {"lightsalmon1",    "#FFA07A",   0xff7aa0ff},
    {"lightsalmon2",    "#EE9572",   0xff7295ee},
    {"lightsalmon3",    "#CD8162",   0xff6281cd},
    {"lightsalmon4",    "#8B5742",   0xff42578b},
    {"lightseagreen",   "#20B2AA",   0xffaab220},
    {"lightskyblue",    "#87CEFA",   0xffface87},
    {"lightskyblue1",   "#B0E2FF",   0xffffe2b0},
    {"lightskyblue2",   "#A4D3EE",   0xffeed3a4},
    {"lightskyblue3",   "#8DB6CD",   0xffcdb68d},
    {"lightskyblue4",   "#607B8B",   0xff8b7b60},
    {"lightslateblue",  "#8470FF",   0xffff7084},
    {"lightslategray",  "#778899",   0xff998877},
    {"lightslategrey",  "#778899",   0xff998877},
    {"lightsteelblue",  "#B0C4DE",   0xffdec4b0},
    {"lightsteelblue1", "#CAE1FF",   0xffffe1ca},
    {"lightsteelblue2", "#BCD2EE",   0xffeed2bc},
    {"lightsteelblue3", "#A2B5CD",   0xffcdb5a2},
    {"lightsteelblue4", "#6E7B8B",   0xff8b7b6e},
    {"lightyellow", "#FFFFE0",   0xffe0ffff},
    {"lightyellow1",    "#FFFFE0",   0xffe0ffff},
    {"lightyellow2",    "#EEEED1",   0xffd1eeee},
    {"lightyellow3",    "#CDCDB4",   0xffb4cdcd},
    {"lightyellow4",    "#8B8B7A",   0xff7a8b8b},
    {"limegreen",   "#32CD32",   0xff32cd32},
    {"linen",   "#FAF0E6",   0xffe6f0fa},
    {"magenta", "#FF00FF",   0xffff00ff},
    {"magenta1",    "#FF00FF",   0xffff00ff},
    {"magenta2",    "#EE00EE",   0xffee00ee},
    {"magenta3",    "#CD00CD",   0xffcd00cd},
    {"magenta4",    "#8B008B",   0xff8b008b},
    {"maroon",  "#B03060",   0xff6030b0},
    {"maroon1", "#FF34B3",   0xffb334ff},
    {"maroon2", "#EE30A7",   0xffa730ee},
    {"maroon3", "#CD2990",   0xff9029cd},
    {"maroon4", "#8B1C62",   0xff621c8b},
    {"mediumaquamarine",    "#66CDAA",   0xffaacd66},
    {"mediumblue",  "#0000CD",   0xffcd0000},
    {"mediumorchid",    "#BA55D3",   0xffd355ba},
    {"mediumorchid1",   "#E066FF",   0xffff66e0},
    {"mediumorchid2",   "#D15FEE",   0xffee5fd1},
    {"mediumorchid3",   "#B452CD",   0xffcd52b4},
    {"mediumorchid4",   "#7A378B",   0xff8b377a},
    {"mediumpurple",    "#9370DB",   0xffdb7093},
    {"mediumpurple1",   "#AB82FF",   0xffff82ab},
    {"mediumpurple2",   "#9F79EE",   0xffee799f},
    {"mediumpurple3",   "#8968CD",   0xffcd6889},
    {"mediumpurple4",   "#5D478B",   0xff8b475d},
    {"mediumseagreen",  "#3CB371",   0xff71b33c},
    {"mediumslateblue", "#7B68EE",   0xffee687b},
    {"mediumspringgreen",   "#00FA9A",   0xff9afa00},
    {"mediumturquoise", "#48D1CC",   0xffccd148},
    {"mediumvioletred", "#C71585",   0xff8515c7},
    {"midnightblue",    "#191970",   0xff701919},
    {"mintcream",   "#F5FFFA",   0xfffafff5},
    {"mistyrose",   "#FFE4E1",   0xffe1e4ff},
    {"mistyrose1",  "#FFE4E1",   0xffe1e4ff},
    {"mistyrose2",  "#EED5D2",   0xffd2d5ee},
    {"mistyrose3",  "#CDB7B5",   0xffb5b7cd},
    {"mistyrose4",  "#8B7D7B",   0xff7b7d8b},
    {"moccasin",    "#FFE4B5",   0xffb5e4ff},
    {"navajowhite", "#FFDEAD",   0xffaddeff},
    {"navajowhite1",    "#FFDEAD",   0xffaddeff},
    {"navajowhite2",    "#EECFA1",   0xffa1cfee},
    {"navajowhite3",    "#CDB38B",   0xff8bb3cd},
    {"navajowhite4",    "#8B795E",   0xff5e798b},
    {"navy",    "#000080",   0xff800000},
    {"navyblue",    "#000080",   0xff800000},
    {"oldlace", "#FDF5E6",   0xffe6f5fd},
    {"olivedrab",   "#6B8E23",   0xff238e6b},
    {"olivedrab1",  "#C0FF3E",   0xff3effc0},
    {"olivedrab2",  "#B3EE3A",   0xff3aeeb3},
    {"olivedrab3",  "#9ACD32",   0xff32cd9a},
    {"olivedrab4",  "#698B22",   0xff228b69},
    {"orange",  "#FFA500",   0xff00a5ff},
    {"orange1", "#FFA500",   0xff00a5ff},
    {"orange2", "#EE9A00",   0xff009aee},
    {"orange3", "#CD8500",   0xff0085cd},
    {"orange4", "#8B5A00",   0xff005a8b},
    {"orangered",   "#FF4500",   0xff0045ff},
    {"orangered1",  "#FF4500",   0xff0045ff},
    {"orangered2",  "#EE4000",   0xff0040ee},
    {"orangered3",  "#CD3700",   0xff0037cd},
    {"orangered4",  "#8B2500",   0xff00258b},
    {"orchid",  "#DA70D6",   0xffd670da},
    {"orchid1", "#FF83FA",   0xfffa83ff},
    {"orchid2", "#EE7AE9",   0xffe97aee},
    {"orchid3", "#CD69C9",   0xffc969cd},
    {"orchid4", "#8B4789",   0xff89478b},
    {"palegoldenrod",   "#EEE8AA",   0xffaae8ee},
    {"palegreen",   "#98FB98",   0xff98fb98},
    {"palegreen1",  "#9AFF9A",   0xff9aff9a},
    {"palegreen2",  "#90EE90",   0xff90ee90},
    {"palegreen3",  "#7CCD7C",   0xff7ccd7c},
    {"palegreen4",  "#548B54",   0xff548b54},
    {"paleturquoise",   "#AFEEEE",   0xffeeeeaf},
    {"paleturquoise1",  "#BBFFFF",   0xffffffbb},
    {"paleturquoise2",  "#AEEEEE",   0xffeeeeae},
    {"paleturquoise3",  "#96CDCD",   0xffcdcd96},
    {"paleturquoise4",  "#668B8B",   0xff8b8b66},
    {"palevioletred",   "#DB7093",   0xff9370db},
    {"palevioletred1",  "#FF82AB",   0xffab82ff},
    {"palevioletred2",  "#EE799F",   0xff9f79ee},
    {"palevioletred3",  "#CD6889",   0xff8968cd},
    {"palevioletred4",  "#8B475D",   0xff5d478b},
    {"papayawhip",  "#FFEFD5",   0xffd5efff},
    {"peachpuff",   "#FFDAB9",   0xffb9daff},
    {"peachpuff1",  "#FFDAB9",   0xffb9daff},
    {"peachpuff2",  "#EECBAD",   0xffadcbee},
    {"peachpuff3",  "#CDAF95",   0xff95afcd},
    {"peachpuff4",  "#8B7765",   0xff65778b},
    {"peru",    "#CD853F",   0xff3f85cd},
    {"pink",    "#FFC0CB",   0xffcbc0ff},
    {"pink1",   "#FFB5C5",   0xffc5b5ff},
    {"pink2",   "#EEA9B8",   0xffb8a9ee},
    {"pink3",   "#CD919E",   0xff9e91cd},
    {"pink4",   "#8B636C",   0xff6c638b},
    {"plum",    "#DDA0DD",   0xffdda0dd},
    {"plum1",   "#FFBBFF",   0xffffbbff},
    {"plum2",   "#EEAEEE",   0xffeeaeee},
    {"plum3",   "#CD96CD",   0xffcd96cd},
    {"plum4",   "#8B668B",   0xff8b668b},
    {"powderblue",  "#B0E0E6",   0xffe6e0b0},
    {"purple",  "#A020F0",   0xfff020a0},
    {"purple1", "#9B30FF",   0xffff309b},
    {"purple2", "#912CEE",   0xffee2c91},
    {"purple3", "#7D26CD",   0xffcd267d},
    {"purple4", "#551A8B",   0xff8b1a55},
    {"red", "#FF0000",   0xff0000ff},
    {"red1",    "#FF0000",   0xff0000ff},
    {"red2",    "#EE0000",   0xff0000ee},
    {"red3",    "#CD0000",   0xff0000cd},
    {"red4",    "#8B0000",   0xff00008b},
    {"rosybrown",   "#BC8F8F",   0xff8f8fbc},
    {"rosybrown1",  "#FFC1C1",   0xffc1c1ff},
    {"rosybrown2",  "#EEB4B4",   0xffb4b4ee},
    {"rosybrown3",  "#CD9B9B",   0xff9b9bcd},
    {"rosybrown4",  "#8B6969",   0xff69698b},
    {"royalblue",   "#4169E1",   0xffe16941},
    {"royalblue1",  "#4876FF",   0xffff7648},
    {"royalblue2",  "#436EEE",   0xffee6e43},
    {"royalblue3",  "#3A5FCD",   0xffcd5f3a},
    {"royalblue4",  "#27408B",   0xff8b4027},
    {"saddlebrown", "#8B4513",   0xff13458b},
    {"salmon",  "#FA8072",   0xff7280fa},
    {"salmon1", "#FF8C69",   0xff698cff},
    {"salmon2", "#EE8262",   0xff6282ee},
    {"salmon3", "#CD7054",   0xff5470cd},
    {"salmon4", "#8B4C39",   0xff394c8b},
    {"sandybrown",  "#F4A460",   0xff60a4f4},
    {"seagreen",    "#2E8B57",   0xff578b2e},
    {"seagreen1",   "#54FF9F",   0xff9fff54},
    {"seagreen2",   "#4EEE94",   0xff94ee4e},
    {"seagreen3",   "#43CD80",   0xff80cd43},
    {"seagreen4",   "#2E8B57",   0xff578b2e},
    {"seashell",    "#FFF5EE",   0xffeef5ff},
    {"seashell1",   "#FFF5EE",   0xffeef5ff},
    {"seashell2",   "#EEE5DE",   0xffdee5ee},
    {"seashell3",   "#CDC5BF",   0xffbfc5cd},
    {"seashell4",   "#8B8682",   0xff82868b},
    {"sienna",  "#A0522D",   0xff2d52a0},
    {"sienna1", "#FF8247",   0xff4782ff},
    {"sienna2", "#EE7942",   0xff4279ee},
    {"sienna3", "#CD6839",   0xff3968cd},
    {"sienna4", "#8B4726",   0xff26478b},
    {"skyblue", "#87CEEB",   0xffebce87},
    {"skyblue1",    "#87CEFF",   0xffffce87},
    {"skyblue2",    "#7EC0EE",   0xffeec07e},
    {"skyblue3",    "#6CA6CD",   0xffcda66c},
    {"skyblue4",    "#4A708B",   0xff8b704a},
    {"slateblue",   "#6A5ACD",   0xffcd5a6a},
    {"slateblue1",  "#836FFF",   0xffff6f83},
    {"slateblue2",  "#7A67EE",   0xffee677a},
    {"slateblue3",  "#6959CD",   0xffcd5969},
    {"slateblue4",  "#473C8B",   0xff8b3c47},
    {"slategray",   "#708090",   0xff908070},
    {"slategray1",  "#C6E2FF",   0xffffe2c6},
    {"slategray2",  "#B9D3EE",   0xffeed3b9},
    {"slategray3",  "#9FB6CD",   0xffcdb69f},
    {"slategray4",  "#6C7B8B",   0xff8b7b6c},
    {"slategrey",   "#708090",   0xff908070},
    {"snow",    "#FFFAFA",   0xfffafaff},
    {"snow1",   "#FFFAFA",   0xfffafaff},
    {"snow2",   "#EEE9E9",   0xffe9e9ee},
    {"snow3",   "#CDC9C9",   0xffc9c9cd},
    {"snow4",   "#8B8989",   0xff89898b},
    {"springgreen", "#00FF7F",   0xff7fff00},
    {"springgreen1",    "#00FF7F",   0xff7fff00},
    {"springgreen2",    "#00EE76",   0xff76ee00},
    {"springgreen3",    "#00CD66",   0xff66cd00},
    {"springgreen4",    "#008B45",   0xff458b00},
    {"steelblue",   "#4682B4",   0xffb48246},
    {"steelblue1",  "#63B8FF",   0xffffb863},
    {"steelblue2",  "#5CACEE",   0xffeeac5c},
    {"steelblue3",  "#4F94CD",   0xffcd944f},
    {"steelblue4",  "#36648B",   0xff8b6436},
    {"tan", "#D2B48C",   0xff8cb4d2},
    {"tan1",    "#FFA54F",   0xff4fa5ff},
    {"tan2",    "#EE9A49",   0xff499aee},
    {"tan3",    "#CD853F",   0xff3f85cd},
    {"tan4",    "#8B5A2B",   0xff2b5a8b},
    {"thistle", "#D8BFD8",   0xffd8bfd8},
    {"thistle1",    "#FFE1FF",   0xffffe1ff},
    {"thistle2",    "#EED2EE",   0xffeed2ee},
    {"thistle3",    "#CDB5CD",   0xffcdb5cd},
    {"thistle4",    "#8B7B8B",   0xff8b7b8b},
    {"tomato",  "#FF6347",   0xff4763ff},
    {"tomato1", "#FF6347",   0xff4763ff},
    {"tomato2", "#EE5C42",   0xff425cee},
    {"tomato3", "#CD4F39",   0xff394fcd},
    {"tomato4", "#8B3626",   0xff26368b},
    {"turquoise",   "#40E0D0",   0xffd0e040},
    {"turquoise1",  "#00F5FF",   0xfffff500},
    {"turquoise2",  "#00E5EE",   0xffeee500},
    {"turquoise3",  "#00C5CD",   0xffcdc500},
    {"turquoise4",  "#00868B",   0xff8b8600},
    {"violet",  "#EE82EE",   0xffee82ee},
    {"violetred",   "#D02090",   0xff9020d0},
    {"violetred1",  "#FF3E96",   0xff963eff},
    {"violetred2",  "#EE3A8C",   0xff8c3aee},
    {"violetred3",  "#CD3278",   0xff7832cd},
    {"violetred4",  "#8B2252",   0xff52228b},
    {"wheat",   "#F5DEB3",   0xffb3def5},
    {"wheat1",  "#FFE7BA",   0xffbae7ff},
    {"wheat2",  "#EED8AE",   0xffaed8ee},
    {"wheat3",  "#CDBA96",   0xff96bacd},
    {"wheat4",  "#8B7E66",   0xff667e8b},
    {"whitesmoke",  "#F5F5F5",   0xfff5f5f5},
    {"yellow",  "#FFFF00",   0xff00ffff},
    {"yellow1", "#FFFF00",   0xff00ffff},
    {"yellow2", "#EEEE00",   0xff00eeee},
    {"yellow3", "#CDCD00",   0xff00cdcd},
    {"yellow4", "#8B8B00",   0xff008b8b},
    {"yellowgreen", "#9ACD32",   0xff32cd9a},
    {NULL,      NULL,       0}
};


/* Hex Digit to Integer Conversion */

static unsigned int hexdigit(int digit)
{
    if('0' <= digit && digit <= '9') return digit - '0';
    if('A' <= digit && digit <= 'F') return 10 + digit - 'A';
    if('a' <= digit && digit <= 'f') return 10 + digit - 'a';
    /*else */ error(_("invalid hex digit in 'color' or 'lty'"));
    return digit; /* never occurs (-Wall) */
}


/* #RRGGBB[AA] String to Internal Color Code */
static rcolor rgb2col(const char *rgb)
{
    unsigned int r = 0, g = 0, b = 0, a = 0; /* -Wall */
    if(rgb[0] != '#')
    error(_("invalid RGB specification"));
    switch (strlen(rgb)) {
    case 9:
    a = 16 * hexdigit(rgb[7]) + hexdigit(rgb[8]);
    case 7:
    r = 16 * hexdigit(rgb[1]) + hexdigit(rgb[2]);
    g = 16 * hexdigit(rgb[3]) + hexdigit(rgb[4]);
    b = 16 * hexdigit(rgb[5]) + hexdigit(rgb[6]);
    break;
    default:
    error(_("invalid RGB specification"));
    }
    if (strlen(rgb) == 7)
    return R_RGB(r, g, b);
    else
    return R_RGBA(r, g, b, a);
}

/* External Color Name to Internal Color Code */

static rcolor name2col(const char *nm)
{
    int i;
    if(strcmp(nm, "NA") == 0 || strcmp(nm, "transparent") == 0)
    /*
     * Paul 01/07/04 (2004-07-01?)
     *
     * Used to be set to NA_INTEGER.
     *
     * Now set to fully transparent white.
     *
     * In some cases, fully transparent gets caught by
     * the graphics engine and no drawing occurs, but
     * in other cases, transparent colours are passed to devices.
     *
     * All devices should respond to fully transparent by
     * not drawing.
     */
    return R_TRANWHITE;
    for(i = 0; ColorDataBase[i].name ; i++) {
    if(StrMatch(ColorDataBase[i].name, nm))
        return ColorDataBase[i].code;
    }
    error(_("invalid color name '%s'"), nm);
    return 0U;      /* never occurs but avoid compiler warnings */
}


/* Internal to External Color Representation */
/* Search the color name database first */
/* If this fails, create an #RRGGBB string */

const char *incol2name(rcolor col)
{
    static char ColBuf[10]; // used for return value

    if(R_OPAQUE(col)) {
    for(int i = 0 ; ColorDataBase[i].name ; i++) {
        if(col == ColorDataBase[i].code)
        return ColorDataBase[i].name;
    }
    ColBuf[0] = '#';
    ColBuf[1] = HexDigits[(col >>  4) & 15];
    ColBuf[2] = HexDigits[(col      ) & 15];
    ColBuf[3] = HexDigits[(col >> 12) & 15];
    ColBuf[4] = HexDigits[(col >>  8) & 15];
    ColBuf[5] = HexDigits[(col >> 20) & 15];
    ColBuf[6] = HexDigits[(col >> 16) & 15];
    ColBuf[7] = '\0';
    return &ColBuf[0];
    } else if (R_TRANSPARENT(col)) {
    return "transparent";
    } else {
    ColBuf[0] = '#';
    ColBuf[1] = HexDigits[(col >>  4) & 15];
    ColBuf[2] = HexDigits[(col  ) & 15];
    ColBuf[3] = HexDigits[(col >> 12) & 15];
    ColBuf[4] = HexDigits[(col >>  8) & 15];
    ColBuf[5] = HexDigits[(col >> 20) & 15];
    ColBuf[6] = HexDigits[(col >> 16) & 15];
    ColBuf[7] = HexDigits[(col >> 28) & 15];
    ColBuf[8] = HexDigits[(col >> 24) & 15];
    ColBuf[9] = '\0';
    return &ColBuf[0];
    }
}

static rcolor str2col(const char *s, rcolor bg)
{
    if(s[0] == '#') return rgb2col(s);
    else if(isdigit((int)s[0])) {
    char *ptr;
    int indx = (int) strtod(s, &ptr);
    if(*ptr) error(_("invalid color specification \"%s\""), s);
    if (indx == 0) return bg;
    return Palette[(indx-1) % PaletteSize];
    } else return name2col(s);
}

rcolor inR_GE_str2col(const char *s)
{
    if (streql(s, "0")) 
    error(_("invalid color specification \"%s\""), s);
    return str2col(s, R_TRANWHITE); // bg is irrelevant
}

/* Convert a sexp element to an R color desc */
/* We Assume that Checks Have Been Done */


rcolor inRGBpar3(SEXP x, int i, rcolor bg)
{
    int indx;
    switch(TYPEOF(x))
    {
    case STRSXP:
    return str2col(CHAR(STRING_ELT(x, i)), bg);
    case LGLSXP:
    indx = LOGICAL(x)[i];
    if (indx == NA_LOGICAL) return R_TRANWHITE;
    break;
    case INTSXP:
    indx = INTEGER(x)[i];
    if (indx == NA_INTEGER) return R_TRANWHITE;
    break;
    case REALSXP:
    if(!R_FINITE(REAL(x)[i])) return R_TRANWHITE;
    indx = (int) REAL(x)[i];
    break;
       default:
       warning(_("supplied color is neither numeric nor character"));
       return bg;
    }
    if (indx < 0) 
    error(_("numerical color values must be >= 0, found %d"), indx);
    if (indx == 0) return bg;
    else return Palette[(indx-1) % PaletteSize];
}

SEXP palette(SEXP val)
{
    SEXP ans;
    rcolor color[MAX_PALETTE_SIZE];
    int i, n;

    if (!isString(val)) error(_("invalid argument type"));
    /* Record the current palette */
    PROTECT(ans = allocVector(STRSXP, PaletteSize));
    for (i = 0; i < PaletteSize; i++)
    SET_STRING_ELT(ans, i, mkChar(incol2name(Palette[i])));
    if ((n = length(val)) == 1) {
    if (StrMatch("default", CHAR(STRING_ELT(val, 0)))) {
        int i;
        for (i = 0; (i < MAX_PALETTE_SIZE) && DefaultPalette[i]; i++)
        Palette[i] = name2col(DefaultPalette[i]);
        PaletteSize = i;
    } else error(_("unknown palette (need >= 2 colors)"));
    }
    else if (n > 1) {
    if (n > MAX_PALETTE_SIZE)
        error(_("maximum number of colors is %d"), MAX_PALETTE_SIZE);
    for (i = 0; i < n; i++) {
        const char *s = CHAR(STRING_ELT(val, i));
        color[i] = (s[0] == '#') ? rgb2col(s) : name2col(s);
    }
    for (i = 0; i < n; i++)
        Palette[i] = color[i];
    PaletteSize = n;
    }
    UNPROTECT(1);
    return ans;
}

/* A version using 'rcolor' type */
SEXP palette2(SEXP val)
{
    SEXP ans = PROTECT(allocVector(INTSXP, PaletteSize));
    int n = length(val), *ians = INTEGER(ans); 
    for (int i = 0; i < PaletteSize; i++) ians[i] = (int)Palette[i];
    if (n) {
    if (TYPEOF(val) != INTSXP) error("requires INTSXP argment");
    if (n > MAX_PALETTE_SIZE)
        error(_("maximum number of colors is %d"), MAX_PALETTE_SIZE);
    for (int i = 0; i < n; i++) Palette[i] = (rcolor)INTEGER(val)[i];
    PaletteSize = n;
    }
    UNPROTECT(1);
    return ans;    
}

SEXP colors(void)
{
    int n;

    for (n = 0; ColorDataBase[n].name != NULL; n++) ;
    SEXP ans = PROTECT(allocVector(STRSXP, n));
    for (n = 0; ColorDataBase[n].name != NULL; n++)
    SET_STRING_ELT(ans, n, mkChar(ColorDataBase[n].name));
    UNPROTECT(1);
    return ans;
}

/* Used to push/pop palette when replaying display list */
static void savePalette(Rboolean save)
{
    if (save)
    for (int i = 0; i < PaletteSize; i++)
        Palette0[i] = Palette[i];
    else
    for (int i = 0; i < PaletteSize; i++)
        Palette[i] = Palette0[i];
}

/* same as src/main/colors.c */
typedef unsigned int (*F1)(SEXP x, int i, unsigned int bg);
typedef const char * (*F2)(unsigned int col);
typedef unsigned int (*F3)(const char *s);
typedef void (*F4)(Rboolean save);

void Rg_set_col_ptrs(F1 f1, F2 f2, F3 f3, F4 f4);

void initPalette(void)
{
    Rg_set_col_ptrs(&inRGBpar3, &incol2name, &inR_GE_str2col, &savePalette);

    /* Initialize the Color Database: we now pre-compute this
    for(int i = 0 ; ColorDataBase[i].name ; i++)
    ColorDataBase[i].code = rgb2col(ColorDataBase[i].rgb);

    Install Default Palette: precomputed
    int i;
    for(i = 0 ; DefaultPalette[i] ; i++)
    Palette[i] = name2col(DefaultPalette[i]);
    PaletteSize = i;  // 8
    */
}