#include "Color.h" #include #include #include #include #include #include #include #include #include class ColorTable : public std::map { public: ColorTable() { map &table = *this; table["white"] = Color(0xff, 0xff, 0xff); table["black"] = Color(0, 0, 0); table["gray"] = Color(0x7f, 0x7f, 0x7f); table["grey"] = Color(0x7f, 0x7f, 0x7f); table["red"] = Color(0xff, 0, 0); table["green"] = Color(0, 0xff, 0); table["blue"] = Color(0, 0, 0xff); table["yellow"] = Color(0xff, 0xff, 0); table["magenta"] = Color(0xff, 0, 0xff); table["fuchsia"] = Color(0xff, 0, 0xff); table["cyan"] = Color(0, 0xff, 0xff); table["aqua"] = Color(0, 0xff, 0xff); table["orange"] = Color(0xff, 0x7f, 0); table["chartreuse"] = Color(0x7f, 0xff, 0); table["pink"] = Color(0xff, 0, 0x7f); table["violet"] = Color(0x7f, 0, 0xff); table["springgreen"] = Color(0, 0xff, 0x7f); table["azure"] = Color(0, 0x7f, 0xff); table["brown"] = Color(0x7f, 0x3f, 0); } }; ColorTable colorTable; // alpha: // 0: don't expect/allow alpha // 1: allow alpha; defaults to 255 (0xff) // -1: allow alpha but ignore - set to to 255 (0xff) Color::Color(const std::string &color, int alpha) { size_t pos = color.find_first_of("+-"); std::string basecolor = color.substr(0, pos); std::string colormod; if (pos != std::string::npos) { colormod = color.substr(pos); } if (basecolor[0] != '#') { // Color name std::transform(basecolor.begin(), basecolor.end(), basecolor.begin(), ::tolower); if (colorTable.count(basecolor) > 0) { *this = colorTable[basecolor]; } else { throw std::runtime_error(std::string("Symbolic color '") + color + "' not known, or color does not begin with #"); } } else { // Html color notation if (std::string::npos != basecolor.find_first_not_of("0123456789abcdefABCDEF", 1)) { throw std::runtime_error("Color value has invalid digits (expected: [0-9a-zA-Z])"); } if (alpha) { if (basecolor.length() != 4 && basecolor.length() != 5 && basecolor.length() != 7 && basecolor.length() != 9) { throw std::runtime_error(std::string("Color '") + color + "' not in the expected format (#xxx, #xxxx, #xxxxxx or #xxxxxxxx)"); } } else { if (basecolor.length() == 5 || basecolor.length() == 9) { throw std::runtime_error(std::string("Color '") + color + "' not in the expected format (#xxx or #xxxxxx) - alpha not allowed"); } if (basecolor.length() != 4 && basecolor.length() != 7) { throw std::runtime_error(std::string("Color '") + color + "' not in the expected format (#xxx or #xxxxxx)"); } } unsigned col = strtoul(basecolor.c_str() + 1, nullptr, 16); if (basecolor.length() < 6) { if (basecolor.length() == 5) { a = (col >> 12) & 0x0f; } else { a = 0x0f; } a |= a << 4; r = (col >> 8) & 0x0f; r |= r << 4; g = (col >> 4) & 0x0f; g |= g << 4; b = (col >> 0) & 0x0f; b |= b << 4; } else { if (basecolor.length() == 9) { a = (col >> 24) & 0xff; } else { a = 0xff; } r = (col >> 16) & 0xff; g = (col >> 8) & 0xff; b = (col >> 0) & 0xff; } if (alpha <= 0) { a = 0xff; } } if (colormod.length() == 0) { return; } std::istringstream iss(colormod); iss >> std::ws; while (!iss.eof()) { double w; char operation; char ccode = 'w'; iss >> operation; iss >> ccode; iss >> w >> std::ws; if (w > 1) { w = w / 255; } if (!strchr("+-", operation) || !strchr("wkrgbcmy", ccode) || w < 0 || w > 1 || iss.fail()) { throw std::runtime_error(std::string("Invalid color modification(s) (") + color + "); expected one or more of [+-][wkrgbcmy] (n = 0..1)"); } double v; if (operation == '+' || operation == '-') { // Mix in a color int mixr = r; int mixg = g; int mixb = b; if (operation == '+') { if (ccode == 'w') { mixr = mixg = mixb = 255; } else if (operation == 'k') { mixr = mixg = mixb = 0; } else if (ccode == 'r') { mixr = 255; } else if (ccode == 'g') { mixg = 255; } else if (ccode == 'b') { mixb = 255; } else if (ccode == 'c') { mixg = mixb = 255; } else if (ccode == 'm') { mixr = mixb = 255; } else if (ccode == 'y') { mixr = mixg = 255; } } else { if (ccode == 'w') { mixr = mixg = mixb = 0; } else if (operation == 'k') { mixr = mixg = mixb = 255; } else if (ccode == 'r') { mixr = 0; } else if (ccode == 'g') { mixg = 0; } else if (ccode == 'b') { mixb = 0; } else if (ccode == 'c') { mixg = mixb = 0; } else if (ccode == 'm') { mixr = mixb = 0; } else if (ccode == 'y') { mixr = mixg = 0; } } v = r * (1 - w) + mixr * w; if (v < 0) { v = 0; } else if (v > 255) { v = 255; } r = int(v + 0.5); v = g * (1 - w) + mixg * w; if (v < 0) { v = 0; } else if (v > 255) { v = 255; } g = int(v + 0.5); v = b * (1 - w) + mixb * w; if (v < 0) { v = 0; } else if (v > 255) { v = 255; } b = int(v + 0.5); } } }