MRPT  1.9.9
CImage_loadXPM.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 /*
10 
11 This file is partially based on source code of ImageMagick by John Cristy. Its
12 license is as follows:
13 
14 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15 % %
16 % %
17 % %
18 % X X PPPP M M %
19 % X X P P MM MM %
20 % X PPPP M M M %
21 % X X P M M %
22 % X X P M M %
23 % %
24 % %
25 % Read/Write ImageMagick Image Format. %
26 % %
27 % %
28 % Software Design %
29 % John Cristy %
30 % July 1992 %
31 % %
32 % %
33 % Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated %
34 % to making software imaging solutions freely available. %
35 % %
36 % Permission is hereby granted, free of charge, to any person obtaining a %
37 % copy of this software and associated documentation files ("ImageMagick"), %
38 % to deal in ImageMagick without restriction, including without limitation %
39 % the rights to use, copy, modify, merge, publish, distribute, sublicense, %
40 % and/or sell copies of ImageMagick, and to permit persons to whom the %
41 % ImageMagick is furnished to do so, subject to the following conditions: %
42 % %
43 % The above copyright notice and this permission notice shall be included in %
44 % all copies or substantial portions of ImageMagick. %
45 % %
46 % The software is provided "as is", without warranty of any kind, express or %
47 % implied, including but not limited to the warranties of merchantability, %
48 % fitness for a particular purpose and noninfringement. In no event shall %
49 % ImageMagick Studio be liable for any claim, damages or other liability, %
50 % whether in an action of contract, tort or otherwise, arising from, out of %
51 % or in connection with ImageMagick or the use or other dealings in %
52 % ImageMagick. %
53 % %
54 % Except as contained in this notice, the name of the ImageMagick Studio %
55 % shall not be used in advertising or otherwise to promote the sale, use or %
56 % other dealings in ImageMagick without prior written authorization from the %
57 % ImageMagick Studio. %
58 % %
59 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60 %
61 %
62 */
63 
64 #include "img-precomp.h" // Precompiled headers
65 
66 #include <mrpt/core/exceptions.h>
67 #include <mrpt/img/CImage.h>
68 #include <cstring>
69 #include <string>
70 #include <unordered_map>
71 
72 #if MRPT_HAS_OPENCV
74 {
75  unsigned char R{0}, G{0}, B{0};
76 };
77 using XPMColorMap = std::unordered_map<std::string, XPMColorMapData>;
78 using Long2LongHash = std::unordered_map<int64_t, int64_t>;
79 
80 static const char* ParseColor(const char* data)
81 {
82  static const char* const targets[] = {"c ", "g ", "g4 ", "m ",
83  "b ", "s ", nullptr};
84 
85  const char *p, *r;
86  const char* q;
87  for (int i = 0; targets[i] != nullptr; i++)
88  {
89  r = data;
90  for (q = targets[i]; *r != '\0'; r++)
91  {
92  if (*r != *q) continue;
93  if (!isspace(*(r - 1))) continue;
94  p = r;
95  for (;;)
96  {
97  if (*q == '\0') return p;
98  if (*p++ != *q++) break;
99  }
100  q = targets[i];
101  }
102  }
103  return nullptr;
104 }
105 
106 /*****************************************************************************\
107 * rgbtab.h *
108 * *
109 * A hard coded rgb.txt. To keep it short I removed all colornames with *
110 * trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer *
111 * Gray ;-). But Grey is recognized on lookups, only on save Gray will be *
112 * used, maybe you want to do some substitue there too. *
113 * *
114 * To save memory the RGBs are coded in one long value, as done by the RGB *
115 * macro. *
116 * *
117 * Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) *
118 \*****************************************************************************/
119 
120 typedef struct
121 {
122  const char* name;
123  uint32_t rgb;
124 } rgbRecord;
125 
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))
129 
130 static const rgbRecord theRGBRecords[] = {
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)}};
367 static const int numTheRGBRecords = 235;
368 
369 static unsigned char ParseHexadecimal(char digit1, char digit2)
370 {
371  unsigned char i1, i2;
372 
373  if (digit1 >= 'a')
374  i1 = (unsigned char)(digit1 - 'a' + 0x0A);
375  else if (digit1 >= 'A')
376  i1 = (unsigned char)(digit1 - 'A' + 0x0A);
377  else
378  i1 = (unsigned char)(digit1 - '0');
379  if (digit2 >= 'a')
380  i2 = (unsigned char)(digit2 - 'a' + 0x0A);
381  else if (digit2 >= 'A')
382  i2 = (unsigned char)(digit2 - 'A' + 0x0A);
383  else
384  i2 = (unsigned char)(digit2 - '0');
385  return (unsigned char)(0x10 * i1 + i2);
386 }
387 
388 static bool GetRGBFromName(
389  const char* inname, bool* isNone, unsigned char* r, unsigned char* g,
390  unsigned char* b)
391 {
392  int left, right, middle;
393  int cmp;
394  uint32_t rgbVal;
395  char* name;
396  char *grey, *p;
397 
398  // Neither #rrggbb nor #rrrrggggbbbb are in database, we parse them directly
399  size_t inname_len = strlen(inname);
400  if (*inname == '#' && (inname_len == 7 || inname_len == 13))
401  {
402  size_t ofs = (inname_len == 7) ? 2 : 4;
403  *r = ParseHexadecimal(inname[1], inname[2]);
404  *g = ParseHexadecimal(inname[1 * ofs + 1], inname[1 * ofs + 2]);
405  *b = ParseHexadecimal(inname[2 * ofs + 1], inname[2 * ofs + 2]);
406  *isNone = false;
407  return true;
408  }
409 
410  name = ::strdup(inname);
411 
412  // theRGBRecords[] has no names with spaces, and no grey, but a
413  // lot of gray...
414 
415  // so first extract ' '
416  while ((p = strchr(name, ' ')) != nullptr)
417  {
418  while (*(p)) // till eof of string
419  {
420  *p = *(p + 1); // copy to the left
421  p++;
422  }
423  }
424  // fold to lower case
425  p = name;
426  while (*p)
427  {
428  *p = (char)tolower(*p);
429  p++;
430  }
431 
432  // substitute Grey with Gray, else rgbtab.h would have more than 100
433  // 'duplicate' entries
434  if ((grey = strstr(name, "grey")) != nullptr) grey[2] = 'a';
435 
436  // check for special 'none' colour:
437  bool found;
438  if (strcmp(name, "none") == 0)
439  {
440  *isNone = true;
441  found = true;
442  }
443  else // not "None"
444  {
445  found = false;
446 
447  // binary search:
448  left = 0;
449  right = numTheRGBRecords - 1;
450  do
451  {
452  middle = (left + right) / 2;
453  cmp = strcmp(name, theRGBRecords[middle].name);
454  if (cmp == 0)
455  {
456  rgbVal = theRGBRecords[middle].rgb;
457  *r = (unsigned char)((rgbVal >> 16) & 0xFF);
458  *g = (unsigned char)((rgbVal >> 8) & 0xFF);
459  *b = (unsigned char)((rgbVal)&0xFF);
460  *isNone = false;
461  found = true;
462  break;
463  }
464  else if (cmp < 0)
465  {
466  right = middle - 1;
467  }
468  else // cmp > 0
469  {
470  left = middle + 1;
471  }
472  } while (left <= right);
473  }
474 
475  free(name);
476 
477  return found;
478 }
479 #endif
480 
481 /** Loads the image from an XPM array, as #include'd from a ".xpm" file.
482  * \sa loadFromFile
483  * \return false on any error */
484 bool mrpt::img::CImage::loadFromXPM(const char* const* xpm_data, bool swap_rb)
485 {
486 #if MRPT_HAS_OPENCV
487  try
488  {
489  ASSERTMSG_(xpm_data, "XPM data is nullptr");
490 
491  char key[64];
492  XPMColorMap clr_tbl;
493  std::string maskKey, keyString;
494 
495  /*
496  * Read hints and initialize structures:
497  */
498  unsigned width, height, colors_cnt, chars_per_pixel;
499  const int count = ::sscanf(
500  xpm_data[0], "%u %u %u %u", &width, &height, &colors_cnt,
501  &chars_per_pixel);
502  if (count != 4 || width * height * colors_cnt == 0)
503  {
504  THROW_EXCEPTION("XPM: incorrect header format!");
505  }
506 
507  // VS: XPM color map this large would be insane, since XPMs are encoded
508  // with 92 possible values on each position, 92^64 is *way* larger space
509  // than 8bit RGB...
510  ASSERTMSG_(
511  chars_per_pixel < 64, "XPM colormaps this large not supported.");
512 
513  this->resize(width, height, CH_RGB);
514  key[chars_per_pixel] = '\0';
515 
516  /*
517  * Create colour map:
518  */
519  XPMColorMapData clr_data;
520  for (size_t i = 0; i < colors_cnt; i++)
521  {
522  const char* xmpColLine = xpm_data[1 + i];
523 
524  // we must have at least " x y" after the colour index, hence +5
525  if (!xmpColLine || strlen(xmpColLine) < chars_per_pixel + 5)
526  {
528  "XPM: incorrect colour description in line %d",
529  (int)(1 + i));
530  }
531 
532  for (size_t i_key = 0; i_key < chars_per_pixel; i_key++)
533  key[i_key] = xmpColLine[i_key];
534  const char* clr_def = ParseColor(xmpColLine + chars_per_pixel);
535 
536  if (clr_def == nullptr)
537  {
539  "XPM: malformed colour definition '%s' at line %d!",
540  xmpColLine, (int)(1 + i));
541  }
542 
543  bool isNone = false;
544  if (!GetRGBFromName(
545  clr_def, &isNone, &clr_data.R, &clr_data.G, &clr_data.B))
546  {
548  "XPM: malformed colour definition '%s' at line %d!",
549  xmpColLine, (int)(1 + i));
550  }
551 
552  keyString = key;
553  if (isNone) maskKey = keyString;
554 
555  clr_tbl[keyString] = clr_data;
556  }
557 
558  // deal with the mask: we must replace pseudo-colour "None" with the
559  // mask colour (which can be any colour not otherwise used in the image)
560  if (!maskKey.empty())
561  {
562  Long2LongHash rgb_table;
563  long rgb;
564  const size_t n = clr_tbl.size();
565  auto iter = clr_tbl.begin();
566  for (size_t i = 0; i < n; ++i, ++iter)
567  {
568  const XPMColorMapData& data = iter->second;
569  rgb = (data.R << 16) + (data.G << 8) + data.B;
570  rgb_table[rgb];
571  }
572  for (rgb = 0; rgb <= 0xffffff && rgb_table.count(rgb); ++rgb)
573  ;
574  if (rgb > 0xffffff)
575  {
576  THROW_EXCEPTION("XPM: no colors left to use for mask!");
577  }
578 
579  XPMColorMapData& maskData = clr_tbl[maskKey];
580  maskData.R = uint8_t(rgb >> 16);
581  maskData.G = uint8_t(rgb >> 8);
582  maskData.B = uint8_t(rgb);
583 
584  // MRPT CImage does not implement masks (!!)
585  // img.SetMaskColour(maskData.R, maskData.G, maskData.B);
586  }
587 
588  /*
589  * Parse image data:
590  */
591  unsigned char* img_data = (*this)(0, 0);
592  auto end = clr_tbl.end();
593 
594  for (size_t j = 0; j < height; j++)
595  {
596  for (size_t i = 0; i < width; i++, img_data += 3)
597  {
598  const char* xpmImgLine = xpm_data[1 + colors_cnt + j];
599  if (!xpmImgLine || strlen(xpmImgLine) < width * chars_per_pixel)
600  {
602  "XPM: truncated image data at line %d!",
603  (int)(1 + colors_cnt + j));
604  return false;
605  }
606 
607  for (size_t i_key = 0; i_key < chars_per_pixel; i_key++)
608  {
609  key[i_key] = xpmImgLine[chars_per_pixel * i + i_key];
610  }
611 
612  keyString = key;
613  auto entry = clr_tbl.find(keyString);
614  if (entry == end)
615  {
616  THROW_EXCEPTION("XPM: Malformed pixel data!");
617 
618  // better return right now as otherwise we risk to flood the
619  // user with error messages as something seems to be
620  // seriously wrong with the file and so we could give this
621  // message for each remaining pixel if we don't bail out
622  return false;
623  }
624 
625  img_data[0] = entry->second.R;
626  img_data[1] = entry->second.G;
627  img_data[2] = entry->second.B;
628  }
629  }
630 
631  if (swap_rb) this->swapRB();
632 
633  return true;
634  }
635  catch (const std::exception& e)
636  {
637  std::cerr << "[CImage::loadFromXPM] " << e.what() << std::endl;
638  return false;
639  }
640 #else
641  MRPT_UNUSED_PARAM(xpm_data);
642  MRPT_UNUSED_PARAM(swap_rb);
643  return false;
644 #endif
645 }
unsigned char B
GLuint GLuint GLsizei count
Definition: glext.h:3532
bool loadFromXPM(const char *const *xpm_array, bool swap_rb=true)
Loads the image from an XPM array, as #include&#39;d from a ".xpm" file.
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
static const rgbRecord theRGBRecords[]
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:3727
GLenum GLsizei n
Definition: glext.h:5136
unsigned char G
static bool GetRGBFromName(const char *inname, bool *isNone, unsigned char *r, unsigned char *g, unsigned char *b)
uint32_t rgb
GLenum GLsizei width
Definition: glext.h:3535
void swapRB()
Swaps red and blue channels.
Definition: CImage.cpp:1606
unsigned char R
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...
Definition: CImage.cpp:253
static const int numTheRGBRecords
GLuint GLuint end
Definition: glext.h:3532
GLubyte g
Definition: glext.h:6372
GLubyte GLubyte b
Definition: glext.h:6372
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
Definition: exceptions.h:108
GLsizei const GLchar ** string
Definition: glext.h:4116
#define myRGB(r, g, b)
GLdouble GLdouble GLdouble r
Definition: glext.h:3711
static const char * ParseColor(const char *data)
std::unordered_map< std::string, XPMColorMapData > XPMColorMap
GLuint const GLchar * name
Definition: glext.h:4068
GLenum GLsizei GLsizei height
Definition: glext.h:3558
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:69
std::unordered_map< int64_t, int64_t > Long2LongHash
static unsigned char ParseHexadecimal(char digit1, char digit2)
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3550
GLfloat GLfloat p
Definition: glext.h:6398
const char * name
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 479715d5b Tue Nov 12 07:26:21 2019 +0100 at mar nov 12 07:30:12 CET 2019