70 #include <unordered_map>    75     unsigned char R{0}, 
G{0}, 
B{0};
    77 using XPMColorMap = std::unordered_map<std::string, XPMColorMapData>;
    82     static const char* 
const targets[] = {
"c ", 
"g ", 
"g4 ",  
"m ",
    87     for (
int i = 0; targets[i] != 
nullptr; i++)
    90         for (q = targets[i]; *r != 
'\0'; r++)
    92             if (*r != *q) 
continue;
    93             if (!isspace(*(r - 1))) 
continue;
    97                 if (*q == 
'\0') 
return p;
    98                 if (*p++ != *q++) 
break;
   126 #define myRGB(r, g, b)                                                \   127     (static_cast<uint32_t>(r) << 16 | static_cast<uint32_t>(g) << 8 | \   128      static_cast<uint32_t>(b))   131     {
"aliceblue", 
myRGB(240, 248, 255)},
   132     {
"antiquewhite", 
myRGB(250, 235, 215)},
   133     {
"aquamarine", 
myRGB(50, 191, 193)},
   134     {
"azure", 
myRGB(240, 255, 255)},
   135     {
"beige", 
myRGB(245, 245, 220)},
   136     {
"bisque", 
myRGB(255, 228, 196)},
   137     {
"black", 
myRGB(0, 0, 0)},
   138     {
"blanchedalmond", 
myRGB(255, 235, 205)},
   139     {
"blue", 
myRGB(0, 0, 255)},
   140     {
"blueviolet", 
myRGB(138, 43, 226)},
   141     {
"brown", 
myRGB(165, 42, 42)},
   142     {
"burlywood", 
myRGB(222, 184, 135)},
   143     {
"cadetblue", 
myRGB(95, 146, 158)},
   144     {
"chartreuse", 
myRGB(127, 255, 0)},
   145     {
"chocolate", 
myRGB(210, 105, 30)},
   146     {
"coral", 
myRGB(255, 114, 86)},
   147     {
"cornflowerblue", 
myRGB(34, 34, 152)},
   148     {
"cornsilk", 
myRGB(255, 248, 220)},
   149     {
"cyan", 
myRGB(0, 255, 255)},
   150     {
"darkgoldenrod", 
myRGB(184, 134, 11)},
   151     {
"darkgreen", 
myRGB(0, 86, 45)},
   152     {
"darkkhaki", 
myRGB(189, 183, 107)},
   153     {
"darkolivegreen", 
myRGB(85, 86, 47)},
   154     {
"darkorange", 
myRGB(255, 140, 0)},
   155     {
"darkorchid", 
myRGB(139, 32, 139)},
   156     {
"darksalmon", 
myRGB(233, 150, 122)},
   157     {
"darkseagreen", 
myRGB(143, 188, 143)},
   158     {
"darkslateblue", 
myRGB(56, 75, 102)},
   159     {
"darkslategray", 
myRGB(47, 79, 79)},
   160     {
"darkturquoise", 
myRGB(0, 166, 166)},
   161     {
"darkviolet", 
myRGB(148, 0, 211)},
   162     {
"deeppink", 
myRGB(255, 20, 147)},
   163     {
"deepskyblue", 
myRGB(0, 191, 255)},
   164     {
"dimgray", 
myRGB(84, 84, 84)},
   165     {
"dodgerblue", 
myRGB(30, 144, 255)},
   166     {
"firebrick", 
myRGB(142, 35, 35)},
   167     {
"floralwhite", 
myRGB(255, 250, 240)},
   168     {
"forestgreen", 
myRGB(80, 159, 105)},
   169     {
"gainsboro", 
myRGB(220, 220, 220)},
   170     {
"ghostwhite", 
myRGB(248, 248, 255)},
   171     {
"gold", 
myRGB(218, 170, 0)},
   172     {
"goldenrod", 
myRGB(239, 223, 132)},
   173     {
"gray", 
myRGB(126, 126, 126)},
   174     {
"gray0", 
myRGB(0, 0, 0)},
   175     {
"gray1", 
myRGB(3, 3, 3)},
   176     {
"gray10", 
myRGB(26, 26, 26)},
   177     {
"gray100", 
myRGB(255, 255, 255)},
   178     {
"gray11", 
myRGB(28, 28, 28)},
   179     {
"gray12", 
myRGB(31, 31, 31)},
   180     {
"gray13", 
myRGB(33, 33, 33)},
   181     {
"gray14", 
myRGB(36, 36, 36)},
   182     {
"gray15", 
myRGB(38, 38, 38)},
   183     {
"gray16", 
myRGB(41, 41, 41)},
   184     {
"gray17", 
myRGB(43, 43, 43)},
   185     {
"gray18", 
myRGB(46, 46, 46)},
   186     {
"gray19", 
myRGB(48, 48, 48)},
   187     {
"gray2", 
myRGB(5, 5, 5)},
   188     {
"gray20", 
myRGB(51, 51, 51)},
   189     {
"gray21", 
myRGB(54, 54, 54)},
   190     {
"gray22", 
myRGB(56, 56, 56)},
   191     {
"gray23", 
myRGB(59, 59, 59)},
   192     {
"gray24", 
myRGB(61, 61, 61)},
   193     {
"gray25", 
myRGB(64, 64, 64)},
   194     {
"gray26", 
myRGB(66, 66, 66)},
   195     {
"gray27", 
myRGB(69, 69, 69)},
   196     {
"gray28", 
myRGB(71, 71, 71)},
   197     {
"gray29", 
myRGB(74, 74, 74)},
   198     {
"gray3", 
myRGB(8, 8, 8)},
   199     {
"gray30", 
myRGB(77, 77, 77)},
   200     {
"gray31", 
myRGB(79, 79, 79)},
   201     {
"gray32", 
myRGB(82, 82, 82)},
   202     {
"gray33", 
myRGB(84, 84, 84)},
   203     {
"gray34", 
myRGB(87, 87, 87)},
   204     {
"gray35", 
myRGB(89, 89, 89)},
   205     {
"gray36", 
myRGB(92, 92, 92)},
   206     {
"gray37", 
myRGB(94, 94, 94)},
   207     {
"gray38", 
myRGB(97, 97, 97)},
   208     {
"gray39", 
myRGB(99, 99, 99)},
   209     {
"gray4", 
myRGB(10, 10, 10)},
   210     {
"gray40", 
myRGB(102, 102, 102)},
   211     {
"gray41", 
myRGB(105, 105, 105)},
   212     {
"gray42", 
myRGB(107, 107, 107)},
   213     {
"gray43", 
myRGB(110, 110, 110)},
   214     {
"gray44", 
myRGB(112, 112, 112)},
   215     {
"gray45", 
myRGB(115, 115, 115)},
   216     {
"gray46", 
myRGB(117, 117, 117)},
   217     {
"gray47", 
myRGB(120, 120, 120)},
   218     {
"gray48", 
myRGB(122, 122, 122)},
   219     {
"gray49", 
myRGB(125, 125, 125)},
   220     {
"gray5", 
myRGB(13, 13, 13)},
   221     {
"gray50", 
myRGB(127, 127, 127)},
   222     {
"gray51", 
myRGB(130, 130, 130)},
   223     {
"gray52", 
myRGB(133, 133, 133)},
   224     {
"gray53", 
myRGB(135, 135, 135)},
   225     {
"gray54", 
myRGB(138, 138, 138)},
   226     {
"gray55", 
myRGB(140, 140, 140)},
   227     {
"gray56", 
myRGB(143, 143, 143)},
   228     {
"gray57", 
myRGB(145, 145, 145)},
   229     {
"gray58", 
myRGB(148, 148, 148)},
   230     {
"gray59", 
myRGB(150, 150, 150)},
   231     {
"gray6", 
myRGB(15, 15, 15)},
   232     {
"gray60", 
myRGB(153, 153, 153)},
   233     {
"gray61", 
myRGB(156, 156, 156)},
   234     {
"gray62", 
myRGB(158, 158, 158)},
   235     {
"gray63", 
myRGB(161, 161, 161)},
   236     {
"gray64", 
myRGB(163, 163, 163)},
   237     {
"gray65", 
myRGB(166, 166, 166)},
   238     {
"gray66", 
myRGB(168, 168, 168)},
   239     {
"gray67", 
myRGB(171, 171, 171)},
   240     {
"gray68", 
myRGB(173, 173, 173)},
   241     {
"gray69", 
myRGB(176, 176, 176)},
   242     {
"gray7", 
myRGB(18, 18, 18)},
   243     {
"gray70", 
myRGB(179, 179, 179)},
   244     {
"gray71", 
myRGB(181, 181, 181)},
   245     {
"gray72", 
myRGB(184, 184, 184)},
   246     {
"gray73", 
myRGB(186, 186, 186)},
   247     {
"gray74", 
myRGB(189, 189, 189)},
   248     {
"gray75", 
myRGB(191, 191, 191)},
   249     {
"gray76", 
myRGB(194, 194, 194)},
   250     {
"gray77", 
myRGB(196, 196, 196)},
   251     {
"gray78", 
myRGB(199, 199, 199)},
   252     {
"gray79", 
myRGB(201, 201, 201)},
   253     {
"gray8", 
myRGB(20, 20, 20)},
   254     {
"gray80", 
myRGB(204, 204, 204)},
   255     {
"gray81", 
myRGB(207, 207, 207)},
   256     {
"gray82", 
myRGB(209, 209, 209)},
   257     {
"gray83", 
myRGB(212, 212, 212)},
   258     {
"gray84", 
myRGB(214, 214, 214)},
   259     {
"gray85", 
myRGB(217, 217, 217)},
   260     {
"gray86", 
myRGB(219, 219, 219)},
   261     {
"gray87", 
myRGB(222, 222, 222)},
   262     {
"gray88", 
myRGB(224, 224, 224)},
   263     {
"gray89", 
myRGB(227, 227, 227)},
   264     {
"gray9", 
myRGB(23, 23, 23)},
   265     {
"gray90", 
myRGB(229, 229, 229)},
   266     {
"gray91", 
myRGB(232, 232, 232)},
   267     {
"gray92", 
myRGB(235, 235, 235)},
   268     {
"gray93", 
myRGB(237, 237, 237)},
   269     {
"gray94", 
myRGB(240, 240, 240)},
   270     {
"gray95", 
myRGB(242, 242, 242)},
   271     {
"gray96", 
myRGB(245, 245, 245)},
   272     {
"gray97", 
myRGB(247, 247, 247)},
   273     {
"gray98", 
myRGB(250, 250, 250)},
   274     {
"gray99", 
myRGB(252, 252, 252)},
   275     {
"green", 
myRGB(0, 255, 0)},
   276     {
"greenyellow", 
myRGB(173, 255, 47)},
   277     {
"honeydew", 
myRGB(240, 255, 240)},
   278     {
"hotpink", 
myRGB(255, 105, 180)},
   279     {
"indianred", 
myRGB(107, 57, 57)},
   280     {
"ivory", 
myRGB(255, 255, 240)},
   281     {
"khaki", 
myRGB(179, 179, 126)},
   282     {
"lavender", 
myRGB(230, 230, 250)},
   283     {
"lavenderblush", 
myRGB(255, 240, 245)},
   284     {
"lawngreen", 
myRGB(124, 252, 0)},
   285     {
"lemonchiffon", 
myRGB(255, 250, 205)},
   286     {
"lightblue", 
myRGB(176, 226, 255)},
   287     {
"lightcoral", 
myRGB(240, 128, 128)},
   288     {
"lightcyan", 
myRGB(224, 255, 255)},
   289     {
"lightgoldenrod", 
myRGB(238, 221, 130)},
   290     {
"lightgoldenrodyellow", 
myRGB(250, 250, 210)},
   291     {
"lightgray", 
myRGB(168, 168, 168)},
   292     {
"lightpink", 
myRGB(255, 182, 193)},
   293     {
"lightsalmon", 
myRGB(255, 160, 122)},
   294     {
"lightseagreen", 
myRGB(32, 178, 170)},
   295     {
"lightskyblue", 
myRGB(135, 206, 250)},
   296     {
"lightslateblue", 
myRGB(132, 112, 255)},
   297     {
"lightslategray", 
myRGB(119, 136, 153)},
   298     {
"lightsteelblue", 
myRGB(124, 152, 211)},
   299     {
"lightyellow", 
myRGB(255, 255, 224)},
   300     {
"limegreen", 
myRGB(0, 175, 20)},
   301     {
"linen", 
myRGB(250, 240, 230)},
   302     {
"magenta", 
myRGB(255, 0, 255)},
   303     {
"maroon", 
myRGB(143, 0, 82)},
   304     {
"mediumaquamarine", 
myRGB(0, 147, 143)},
   305     {
"mediumblue", 
myRGB(50, 50, 204)},
   306     {
"mediumforestgreen", 
myRGB(50, 129, 75)},
   307     {
"mediumgoldenrod", 
myRGB(209, 193, 102)},
   308     {
"mediumorchid", 
myRGB(189, 82, 189)},
   309     {
"mediumpurple", 
myRGB(147, 112, 219)},
   310     {
"mediumseagreen", 
myRGB(52, 119, 102)},
   311     {
"mediumslateblue", 
myRGB(106, 106, 141)},
   312     {
"mediumspringgreen", 
myRGB(35, 142, 35)},
   313     {
"mediumturquoise", 
myRGB(0, 210, 210)},
   314     {
"mediumvioletred", 
myRGB(213, 32, 121)},
   315     {
"midnightblue", 
myRGB(47, 47, 100)},
   316     {
"mintcream", 
myRGB(245, 255, 250)},
   317     {
"mistyrose", 
myRGB(255, 228, 225)},
   318     {
"moccasin", 
myRGB(255, 228, 181)},
   319     {
"navajowhite", 
myRGB(255, 222, 173)},
   320     {
"navy", 
myRGB(35, 35, 117)},
   321     {
"navyblue", 
myRGB(35, 35, 117)},
   322     {
"oldlace", 
myRGB(253, 245, 230)},
   323     {
"olivedrab", 
myRGB(107, 142, 35)},
   324     {
"orange", 
myRGB(255, 135, 0)},
   325     {
"orangered", 
myRGB(255, 69, 0)},
   326     {
"orchid", 
myRGB(239, 132, 239)},
   327     {
"palegoldenrod", 
myRGB(238, 232, 170)},
   328     {
"palegreen", 
myRGB(115, 222, 120)},
   329     {
"paleturquoise", 
myRGB(175, 238, 238)},
   330     {
"palevioletred", 
myRGB(219, 112, 147)},
   331     {
"papayawhip", 
myRGB(255, 239, 213)},
   332     {
"peachpuff", 
myRGB(255, 218, 185)},
   333     {
"peru", 
myRGB(205, 133, 63)},
   334     {
"pink", 
myRGB(255, 181, 197)},
   335     {
"plum", 
myRGB(197, 72, 155)},
   336     {
"powderblue", 
myRGB(176, 224, 230)},
   337     {
"purple", 
myRGB(160, 32, 240)},
   338     {
"red", 
myRGB(255, 0, 0)},
   339     {
"rosybrown", 
myRGB(188, 143, 143)},
   340     {
"royalblue", 
myRGB(65, 105, 225)},
   341     {
"saddlebrown", 
myRGB(139, 69, 19)},
   342     {
"salmon", 
myRGB(233, 150, 122)},
   343     {
"sandybrown", 
myRGB(244, 164, 96)},
   344     {
"seagreen", 
myRGB(82, 149, 132)},
   345     {
"seashell", 
myRGB(255, 245, 238)},
   346     {
"sienna", 
myRGB(150, 82, 45)},
   347     {
"silver", 
myRGB(192, 192, 192)},
   348     {
"skyblue", 
myRGB(114, 159, 255)},
   349     {
"slateblue", 
myRGB(126, 136, 171)},
   350     {
"slategray", 
myRGB(112, 128, 144)},
   351     {
"snow", 
myRGB(255, 250, 250)},
   352     {
"springgreen", 
myRGB(65, 172, 65)},
   353     {
"steelblue", 
myRGB(84, 112, 170)},
   354     {
"tan", 
myRGB(222, 184, 135)},
   355     {
"thistle", 
myRGB(216, 191, 216)},
   356     {
"tomato", 
myRGB(255, 99, 71)},
   357     {
"transparent", 
myRGB(0, 0, 1)},
   358     {
"turquoise", 
myRGB(25, 204, 223)},
   359     {
"violet", 
myRGB(156, 62, 206)},
   360     {
"violetred", 
myRGB(243, 62, 150)},
   361     {
"wheat", 
myRGB(245, 222, 179)},
   362     {
"white", 
myRGB(255, 255, 255)},
   363     {
"whitesmoke", 
myRGB(245, 245, 245)},
   364     {
"yellow", 
myRGB(255, 255, 0)},
   365     {
"yellowgreen", 
myRGB(50, 216, 56)},
   366     {
nullptr, 
myRGB(0, 0, 0)}};
   371     unsigned char i1, i2;
   374         i1 = (
unsigned char)(digit1 - 
'a' + 0x0A);
   375     else if (digit1 >= 
'A')
   376         i1 = (
unsigned char)(digit1 - 
'A' + 0x0A);
   378         i1 = (
unsigned char)(digit1 - 
'0');
   380         i2 = (
unsigned char)(digit2 - 
'a' + 0x0A);
   381     else if (digit2 >= 
'A')
   382         i2 = (
unsigned char)(digit2 - 
'A' + 0x0A);
   384         i2 = (
unsigned char)(digit2 - 
'0');
   385     return (
unsigned char)(0x10 * i1 + i2);
   389     const char* inname, 
bool* isNone, 
unsigned char* r, 
unsigned char* g,
   392     int left, right, middle;
   399     size_t inname_len = strlen(inname);
   400     if (*inname == 
'#' && (inname_len == 7 || inname_len == 13))
   402         size_t ofs = (inname_len == 7) ? 2 : 4;
   410     name = ::strdup(inname);
   416     while ((p = strchr(name, 
' ')) != 
nullptr)
   428         *p = (char)tolower(*p);
   434     if ((grey = strstr(name, 
"grey")) != 
nullptr) grey[2] = 
'a';
   438     if (strcmp(name, 
"none") == 0)
   452             middle = (left + right) / 2;
   457                 *r = (
unsigned char)((rgbVal >> 16) & 0xFF);
   458                 *g = (
unsigned char)((rgbVal >> 8) & 0xFF);
   459                 *b = (
unsigned char)((rgbVal)&0xFF);
   472         } 
while (left <= right);
   485     [[maybe_unused]] 
const char* 
const* xpm_data, [[maybe_unused]] 
bool swap_rb)
   494         std::string maskKey, keyString;
   499         unsigned width, height, colors_cnt, chars_per_pixel;
   500         const int count = ::sscanf(
   501             xpm_data[0], 
"%u %u %u %u", &width, &height, &colors_cnt,
   503         if (count != 4 || width * height * colors_cnt == 0)
   512             chars_per_pixel < 64, 
"XPM colormaps this large not supported.");
   515         key[chars_per_pixel] = 
'\0';
   521         for (
size_t i = 0; i < colors_cnt; i++)
   523             const char* xmpColLine = xpm_data[1 + i];
   526             if (!xmpColLine || strlen(xmpColLine) < chars_per_pixel + 5)
   529                     "XPM: incorrect colour description in line %d",
   533             for (
size_t i_key = 0; i_key < chars_per_pixel; i_key++)
   534                 key[i_key] = xmpColLine[i_key];
   535             const char* clr_def = 
ParseColor(xmpColLine + chars_per_pixel);
   537             if (clr_def == 
nullptr)
   540                     "XPM: malformed colour definition '%s' at line %d!",
   541                     xmpColLine, (
int)(1 + i));
   546                     clr_def, &isNone, &clr_data.
R, &clr_data.
G, &clr_data.
B))
   549                     "XPM: malformed colour definition '%s' at line %d!",
   550                     xmpColLine, (
int)(1 + i));
   554             if (isNone) maskKey = keyString;
   556             clr_tbl[keyString] = clr_data;
   561         if (!maskKey.empty())
   565             const size_t n = clr_tbl.size();
   566             auto iter = clr_tbl.begin();
   567             for (
size_t i = 0; i < n; ++i, ++iter)
   573             for (rgb = 0; rgb <= 0xffffff && rgb_table.count(rgb); ++rgb)
   581             maskData.
R = uint8_t(rgb >> 16);
   582             maskData.
G = uint8_t(rgb >> 8);
   583             maskData.
B = uint8_t(rgb);
   592         unsigned char* img_data = (*this)(0, 0);
   593         auto end = clr_tbl.end();
   595         for (
size_t j = 0; j < height; j++)
   597             for (
size_t i = 0; i < width; i++, img_data += 3)
   599                 const char* xpmImgLine = xpm_data[1 + colors_cnt + j];
   600                 if (!xpmImgLine || strlen(xpmImgLine) < width * chars_per_pixel)
   603                         "XPM: truncated image data at line %d!",
   604                         (
int)(1 + colors_cnt + j));
   608                 for (
size_t i_key = 0; i_key < chars_per_pixel; i_key++)
   610                     key[i_key] = xpmImgLine[chars_per_pixel * i + i_key];
   614                 auto entry = clr_tbl.find(keyString);
   626                 img_data[0] = entry->second.R;
   627                 img_data[1] = entry->second.G;
   628                 img_data[2] = entry->second.B;
   632         if (swap_rb) this->
swapRB();
   636     catch (
const std::exception& e)
   638         std::cerr << 
"[CImage::loadFromXPM] " << e.what() << std::endl;
 
bool loadFromXPM(const char *const *xpm_array, bool swap_rb=true)
Loads the image from an XPM array, as #include'd from a ".xpm" file. 
 
#define THROW_EXCEPTION(msg)
 
static const rgbRecord theRGBRecords[]
 
static bool GetRGBFromName(const char *inname, bool *isNone, unsigned char *r, unsigned char *g, unsigned char *b)
 
void swapRB()
Swaps red and blue channels. 
 
void resize(std::size_t width, std::size_t height, TImageChannels nChannels, PixelDepth depth=PixelDepth::D8U)
Changes the size of the image, erasing previous contents (does NOT scale its current content...
 
static const int numTheRGBRecords
 
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism. 
 
const_iterator end() const
 
static const char * ParseColor(const char *data)
 
std::unordered_map< std::string, XPMColorMapData > XPMColorMap
 
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
 
std::unordered_map< int64_t, int64_t > Long2LongHash
 
static unsigned char ParseHexadecimal(char digit1, char digit2)
 
static struct FontData data