image_xpm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. /*
  2. * File : image_xpm.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2009, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2009-10-16 Bernard first version
  13. */
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <rtgui/filerw.h>
  17. #include <rtgui/image_xpm.h>
  18. #include <rtgui/rtgui_system.h>
  19. #define XPM_MAGIC_LEN 9
  20. static rt_bool_t rtgui_image_xpm_check(struct rtgui_filerw * file);
  21. static rt_bool_t rtgui_image_xpm_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load);
  22. static void rtgui_image_xpm_unload(struct rtgui_image* image);
  23. static void rtgui_image_xpm_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* rect);
  24. struct rtgui_image_engine rtgui_image_xpm_engine =
  25. {
  26. "xpm",
  27. {RT_NULL},
  28. rtgui_image_xpm_check,
  29. rtgui_image_xpm_load,
  30. rtgui_image_xpm_unload,
  31. rtgui_image_xpm_blit
  32. };
  33. struct rgb_item
  34. {
  35. char *name;
  36. int r;
  37. int g;
  38. int b;
  39. };
  40. const struct rgb_item rgbRecord[234] = {
  41. {"AliceBlue", 240, 248, 255},
  42. {"AntiqueWhite", 250, 235, 215},
  43. {"Aquamarine", 50, 191, 193},
  44. {"Azure", 240, 255, 255},
  45. {"Beige", 245, 245, 220},
  46. {"Bisque", 255, 228, 196},
  47. {"Black", 0, 0, 0},
  48. {"BlanchedAlmond", 255, 235, 205},
  49. {"Blue", 0, 0, 255},
  50. {"BlueViolet", 138, 43, 226},
  51. {"Brown", 165, 42, 42},
  52. {"burlywood", 222, 184, 135},
  53. {"CadetBlue", 95, 146, 158},
  54. {"chartreuse", 127, 255, 0},
  55. {"chocolate", 210, 105, 30},
  56. {"Coral", 255, 114, 86},
  57. {"CornflowerBlue", 34, 34, 152},
  58. {"cornsilk", 255, 248, 220},
  59. {"Cyan", 0, 255, 255},
  60. {"DarkGoldenrod", 184, 134, 11},
  61. {"DarkGreen", 0, 86, 45},
  62. {"DarkKhaki", 189, 183, 107},
  63. {"DarkOliveGreen", 85, 86, 47},
  64. {"DarkOrange", 255, 140, 0},
  65. {"DarkOrchid", 139, 32, 139},
  66. {"DarkSalmon", 233, 150, 122},
  67. {"DarkSeaGreen", 143, 188, 143},
  68. {"DarkSlateBlue", 56, 75, 102},
  69. {"DarkSlateGray", 47, 79, 79},
  70. {"DarkTurquoise", 0, 166, 166},
  71. {"DarkViolet", 148, 0, 211},
  72. {"DeepPink", 255, 20, 147},
  73. {"DeepSkyBlue", 0, 191, 255},
  74. {"DimGray", 84, 84, 84},
  75. {"DodgerBlue", 30, 144, 255},
  76. {"Firebrick", 142, 35, 35},
  77. {"FloralWhite", 255, 250, 240},
  78. {"ForestGreen", 80, 159, 105},
  79. {"gainsboro", 220, 220, 220},
  80. {"GhostWhite", 248, 248, 255},
  81. {"Gold", 218, 170, 0},
  82. {"Goldenrod", 239, 223, 132},
  83. {"Gray", 126, 126, 126},
  84. {"Gray0", 0, 0, 0},
  85. {"Gray1", 3, 3, 3},
  86. {"Gray10", 26, 26, 26},
  87. {"Gray100", 255, 255, 255},
  88. {"Gray11", 28, 28, 28},
  89. {"Gray12", 31, 31, 31},
  90. {"Gray13", 33, 33, 33},
  91. {"Gray14", 36, 36, 36},
  92. {"Gray15", 38, 38, 38},
  93. {"Gray16", 41, 41, 41},
  94. {"Gray17", 43, 43, 43},
  95. {"Gray18", 46, 46, 46},
  96. {"Gray19", 48, 48, 48},
  97. {"Gray2", 5, 5, 5},
  98. {"Gray20", 51, 51, 51},
  99. {"Gray21", 54, 54, 54},
  100. {"Gray22", 56, 56, 56},
  101. {"Gray23", 59, 59, 59},
  102. {"Gray24", 61, 61, 61},
  103. {"Gray25", 64, 64, 64},
  104. {"Gray26", 66, 66, 66},
  105. {"Gray27", 69, 69, 69},
  106. {"Gray28", 71, 71, 71},
  107. {"Gray29", 74, 74, 74},
  108. {"Gray3", 8, 8, 8},
  109. {"Gray30", 77, 77, 77},
  110. {"Gray31", 79, 79, 79},
  111. {"Gray32", 82, 82, 82},
  112. {"Gray33", 84, 84, 84},
  113. {"Gray34", 87, 87, 87},
  114. {"Gray35", 89, 89, 89},
  115. {"Gray36", 92, 92, 92},
  116. {"Gray37", 94, 94, 94},
  117. {"Gray38", 97, 97, 97},
  118. {"Gray39", 99, 99, 99},
  119. {"Gray4", 10, 10, 10},
  120. {"Gray40", 102, 102, 102},
  121. {"Gray41", 105, 105, 105},
  122. {"Gray42", 107, 107, 107},
  123. {"Gray43", 110, 110, 110},
  124. {"Gray44", 112, 112, 112},
  125. {"Gray45", 115, 115, 115},
  126. {"Gray46", 117, 117, 117},
  127. {"Gray47", 120, 120, 120},
  128. {"Gray48", 122, 122, 122},
  129. {"Gray49", 125, 125, 125},
  130. {"Gray5", 13, 13, 13},
  131. {"Gray50", 127, 127, 127},
  132. {"Gray51", 130, 130, 130},
  133. {"Gray52", 133, 133, 133},
  134. {"Gray53", 135, 135, 135},
  135. {"Gray54", 138, 138, 138},
  136. {"Gray55", 140, 140, 140},
  137. {"Gray56", 143, 143, 143},
  138. {"Gray57", 145, 145, 145},
  139. {"Gray58", 148, 148, 148},
  140. {"Gray59", 150, 150, 150},
  141. {"Gray6", 15, 15, 15},
  142. {"Gray60", 153, 153, 153},
  143. {"Gray61", 156, 156, 156},
  144. {"Gray62", 158, 158, 158},
  145. {"Gray63", 161, 161, 161},
  146. {"Gray64", 163, 163, 163},
  147. {"Gray65", 166, 166, 166},
  148. {"Gray66", 168, 168, 168},
  149. {"Gray67", 171, 171, 171},
  150. {"Gray68", 173, 173, 173},
  151. {"Gray69", 176, 176, 176},
  152. {"Gray7", 18, 18, 18},
  153. {"Gray70", 179, 179, 179},
  154. {"Gray71", 181, 181, 181},
  155. {"Gray72", 184, 184, 184},
  156. {"Gray73", 186, 186, 186},
  157. {"Gray74", 189, 189, 189},
  158. {"Gray75", 191, 191, 191},
  159. {"Gray76", 194, 194, 194},
  160. {"Gray77", 196, 196, 196},
  161. {"Gray78", 199, 199, 199},
  162. {"Gray79", 201, 201, 201},
  163. {"Gray8", 20, 20, 20},
  164. {"Gray80", 204, 204, 204},
  165. {"Gray81", 207, 207, 207},
  166. {"Gray82", 209, 209, 209},
  167. {"Gray83", 212, 212, 212},
  168. {"Gray84", 214, 214, 214},
  169. {"Gray85", 217, 217, 217},
  170. {"Gray86", 219, 219, 219},
  171. {"Gray87", 222, 222, 222},
  172. {"Gray88", 224, 224, 224},
  173. {"Gray89", 227, 227, 227},
  174. {"Gray9", 23, 23, 23},
  175. {"Gray90", 229, 229, 229},
  176. {"Gray91", 232, 232, 232},
  177. {"Gray92", 235, 235, 235},
  178. {"Gray93", 237, 237, 237},
  179. {"Gray94", 240, 240, 240},
  180. {"Gray95", 242, 242, 242},
  181. {"Gray96", 245, 245, 245},
  182. {"Gray97", 247, 247, 247},
  183. {"Gray98", 250, 250, 250},
  184. {"Gray99", 252, 252, 252},
  185. {"Green", 0, 255, 0},
  186. {"GreenYellow", 173, 255, 47},
  187. {"honeydew", 240, 255, 240},
  188. {"HotPink", 255, 105, 180},
  189. {"IndianRed", 107, 57, 57},
  190. {"ivory", 255, 255, 240},
  191. {"Khaki", 179, 179, 126},
  192. {"lavender", 230, 230, 250},
  193. {"LavenderBlush", 255, 240, 245},
  194. {"LawnGreen", 124, 252, 0},
  195. {"LemonChiffon", 255, 250, 205},
  196. {"LightBlue", 176, 226, 255},
  197. {"LightCoral", 240, 128, 128},
  198. {"LightCyan", 224, 255, 255},
  199. {"LightGoldenrod", 238, 221, 130},
  200. {"LightGoldenrodYellow", 250, 250, 210},
  201. {"LightGray", 168, 168, 168},
  202. {"LightPink", 255, 182, 193},
  203. {"LightSalmon", 255, 160, 122},
  204. {"LightSeaGreen", 32, 178, 170},
  205. {"LightSkyBlue", 135, 206, 250},
  206. {"LightSlateBlue", 132, 112, 255},
  207. {"LightSlateGray", 119, 136, 153},
  208. {"LightSteelBlue", 124, 152, 211},
  209. {"LightYellow", 255, 255, 224},
  210. {"LimeGreen", 0, 175, 20},
  211. {"linen", 250, 240, 230},
  212. {"Magenta", 255, 0, 255},
  213. {"Maroon", 143, 0, 82},
  214. {"MediumAquamarine", 0, 147, 143},
  215. {"MediumBlue", 50, 50, 204},
  216. {"MediumForestGreen", 50, 129, 75},
  217. {"MediumGoldenrod", 209, 193, 102},
  218. {"MediumOrchid", 189, 82, 189},
  219. {"MediumPurple", 147, 112, 219},
  220. {"MediumSeaGreen", 52, 119, 102},
  221. {"MediumSlateBlue", 106, 106, 141},
  222. {"MediumSpringGreen", 35, 142, 35},
  223. {"MediumTurquoise", 0, 210, 210},
  224. {"MediumVioletRed", 213, 32, 121},
  225. {"MidnightBlue", 47, 47, 100},
  226. {"MintCream", 245, 255, 250},
  227. {"MistyRose", 255, 228, 225},
  228. {"moccasin", 255, 228, 181},
  229. {"NavajoWhite", 255, 222, 173},
  230. {"Navy", 35, 35, 117},
  231. {"NavyBlue", 35, 35, 117},
  232. {"OldLace", 253, 245, 230},
  233. {"OliveDrab", 107, 142, 35},
  234. {"Orange", 255, 135, 0},
  235. {"OrangeRed", 255, 69, 0},
  236. {"Orchid", 239, 132, 239},
  237. {"PaleGoldenrod", 238, 232, 170},
  238. {"PaleGreen", 115, 222, 120},
  239. {"PaleTurquoise", 175, 238, 238},
  240. {"PaleVioletRed", 219, 112, 147},
  241. {"PapayaWhip", 255, 239, 213},
  242. {"PeachPuff", 255, 218, 185},
  243. {"peru", 205, 133, 63},
  244. {"Pink", 255, 181, 197},
  245. {"Plum", 197, 72, 155},
  246. {"PowderBlue", 176, 224, 230},
  247. {"purple", 160, 32, 240},
  248. {"Red", 255, 0, 0},
  249. {"RosyBrown", 188, 143, 143},
  250. {"RoyalBlue", 65, 105, 225},
  251. {"SaddleBrown", 139, 69, 19},
  252. {"Salmon", 233, 150, 122},
  253. {"SandyBrown", 244, 164, 96},
  254. {"SeaGreen", 82, 149, 132},
  255. {"seashell", 255, 245, 238},
  256. {"Sienna", 150, 82, 45},
  257. {"SkyBlue", 114, 159, 255},
  258. {"SlateBlue", 126, 136, 171},
  259. {"SlateGray", 112, 128, 144},
  260. {"snow", 255, 250, 250},
  261. {"SpringGreen", 65, 172, 65},
  262. {"SteelBlue", 84, 112, 170},
  263. {"Tan", 222, 184, 135},
  264. {"Thistle", 216, 191, 216},
  265. {"tomato", 255, 99, 71},
  266. {"Transparent", 0, 0, 1},
  267. {"Turquoise", 25, 204, 223},
  268. {"Violet", 156, 62, 206},
  269. {"VioletRed", 243, 62, 150},
  270. {"Wheat", 245, 222, 179},
  271. {"White", 255, 255, 255},
  272. {"WhiteSmoke", 245, 245, 245},
  273. {"Yellow", 255, 255, 0},
  274. {"YellowGreen", 50, 216, 56}
  275. };
  276. /* Hash table to look up colors from pixel strings */
  277. #define STARTING_HASH_SIZE 256
  278. struct hash_entry
  279. {
  280. char key[10];
  281. rtgui_color_t color;
  282. struct hash_entry *next;
  283. };
  284. struct color_hash
  285. {
  286. struct hash_entry **table;
  287. struct hash_entry *entries; /* array of all entries */
  288. struct hash_entry *next_free;
  289. int size;
  290. int maxnum;
  291. };
  292. static int hash_key(const char *key, int cpp, int size)
  293. {
  294. int hash;
  295. hash = 0;
  296. while ( cpp-- > 0 )
  297. {
  298. hash = hash * 33 + *key++;
  299. }
  300. return hash & (size - 1);
  301. }
  302. static struct color_hash *create_colorhash(int maxnum)
  303. {
  304. int bytes, s;
  305. struct color_hash *hash;
  306. /* we know how many entries we need, so we can allocate
  307. everything here */
  308. hash = rtgui_malloc(sizeof *hash);
  309. if(!hash) return RT_NULL;
  310. /* use power-of-2 sized hash table for decoding speed */
  311. for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1) ;
  312. hash->size = s;
  313. hash->maxnum = maxnum;
  314. bytes = hash->size * sizeof(struct hash_entry **);
  315. hash->entries = RT_NULL; /* in case rt_malloc fails */
  316. hash->table = rtgui_malloc(bytes);
  317. if(!hash->table) return RT_NULL;
  318. rt_memset(hash->table, 0, bytes);
  319. hash->entries = rtgui_malloc(maxnum * sizeof(struct hash_entry));
  320. if(!hash->entries) return RT_NULL;
  321. hash->next_free = hash->entries;
  322. return hash;
  323. }
  324. static int add_colorhash(struct color_hash *hash,
  325. char *key, int cpp, rtgui_color_t *color)
  326. {
  327. int index = hash_key(key, cpp, hash->size);
  328. struct hash_entry *e = hash->next_free++;
  329. e->color = *color;
  330. rt_memset(e->key, 0, sizeof(e->key));
  331. rt_strncpy(e->key, key, cpp);
  332. e->next = hash->table[index];
  333. hash->table[index] = e;
  334. return 1;
  335. }
  336. static void get_colorhash(struct color_hash *hash, const char *key, int cpp, rtgui_color_t* c)
  337. {
  338. struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
  339. while(entry)
  340. {
  341. if(rt_memcmp(key, entry->key, cpp) == 0)
  342. {
  343. *c = entry->color;
  344. return;
  345. }
  346. entry = entry->next;
  347. }
  348. return ; /* garbage in - garbage out */
  349. }
  350. static void free_colorhash(struct color_hash *hash)
  351. {
  352. if(hash && hash->table)
  353. {
  354. rtgui_free(hash->table);
  355. rtgui_free(hash->entries);
  356. rtgui_free(hash);
  357. }
  358. }
  359. #if defined(_MSC_VER) || defined(__CC_ARM)
  360. int strcasecmp( const char* s1, const char* s2 )
  361. {
  362. register unsigned int x2;
  363. register unsigned int x1;
  364. while (1) {
  365. x2 = *s2 - 'A'; if (x2 < 26u) x2 += 32;
  366. x1 = *s1 - 'A'; if (x1 < 26u) x1 += 32;
  367. s1++; s2++;
  368. if (x2 != x1)
  369. break;
  370. if (x1 == (unsigned int)-'A')
  371. break;
  372. }
  373. return x1 - x2;
  374. }
  375. #endif
  376. static int hex2int (char *str)
  377. {
  378. int i = 0;
  379. int r = 0;
  380. for (i = 0; i < 2; i++)
  381. {
  382. if (str[i] >= '0' && str[i] <= '9') r += str[i] - '0';
  383. else if (str[i] >= 'a' && str[i] <= 'f') r += str[i] - 'a' + 10;
  384. else if (str[i] >= 'A' && str[i] <= 'F') r += str[i] - 'A' + 10;
  385. if (!i) r *= 16;
  386. }
  387. return r;
  388. }
  389. void rtgui_image_xpm_init()
  390. {
  391. /* register xpm engine */
  392. rtgui_image_register_engine(&rtgui_image_xpm_engine);
  393. }
  394. static rt_bool_t rtgui_image_xpm_check(struct rtgui_filerw* file)
  395. {
  396. #if 0
  397. rt_uint8_t buffer[XPM_MAGIC_LEN];
  398. rt_size_t start;
  399. rt_bool_t result;
  400. result = RT_FALSE;
  401. start = rtgui_filerw_tell(file);
  402. /* seek to the begining of file */
  403. if (start != 0) rtgui_filerw_seek(file, 0, SEEK_SET);
  404. rtgui_filerw_read(file, &buffer[0], XPM_MAGIC_LEN, 1);
  405. if (rt_memcmp(buffer, "/* XPM */", (rt_ubase_t)XPM_MAGIC_LEN) == 0)
  406. result = RT_TRUE;
  407. rtgui_filerw_seek(file, start, SEEK_SET);
  408. return result;
  409. #else
  410. /* we can not check image type for memory file */
  411. return RT_TRUE;
  412. #endif
  413. }
  414. static rt_bool_t rtgui_image_xpm_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load)
  415. {
  416. const char **xpm;
  417. const char *buf;
  418. const char *buf_tmp;
  419. int w, h;
  420. int colors = 0;
  421. int colors_pp = 0;
  422. int i, j;
  423. /* color hash table */
  424. struct color_hash *colors_table = RT_NULL;
  425. if (image == RT_NULL) return RT_FALSE;
  426. xpm = (const char **)rtgui_filerw_mem_getdata(file);
  427. if (xpm == RT_NULL) return RT_FALSE;
  428. /* set image engine */
  429. image->engine = &rtgui_image_xpm_engine;
  430. /* parse xpm image */
  431. sscanf(xpm[0], "%d %d %d %d", &w, &h, &colors, &colors_pp);
  432. image->w = w;
  433. image->h = h;
  434. /* build color table */
  435. colors_table = create_colorhash(colors);
  436. if (!colors_table)
  437. {
  438. return RT_FALSE;
  439. }
  440. for (i = 0; i < colors; i++)
  441. {
  442. char color_name[10];
  443. rtgui_color_t c = 0;
  444. buf = xpm[i + 1];
  445. for (j = 0; j < colors_pp; j++)
  446. {
  447. color_name[j] = buf[j];
  448. }
  449. color_name[j] = '\0';
  450. /* build rtgui_color */
  451. if ((buf_tmp = strstr(buf, "c #")) != RT_NULL)
  452. {
  453. char color_hex[10];
  454. /* hexadecimal color value */
  455. sscanf(buf_tmp, "c #%s", color_hex);
  456. c = RTGUI_ARGB(0, hex2int(color_hex),
  457. hex2int(color_hex + 2),
  458. hex2int(color_hex + 4));
  459. }
  460. else if ((buf_tmp = strstr(buf, "c ")) != RT_NULL)
  461. {
  462. int k;
  463. /* color name */
  464. char rgbname[30];
  465. sscanf(buf_tmp, "c %s", rgbname);
  466. if (strcasecmp(rgbname, "None") == 0)
  467. {
  468. goto color_none;
  469. }
  470. for (k = 0; k < 234; k++)
  471. {
  472. if (strcasecmp(rgbname, rgbRecord[k].name) == 0)
  473. {
  474. c = RTGUI_ARGB(0, rgbRecord[k].r,
  475. rgbRecord[k].g,
  476. rgbRecord[k].b);
  477. break;
  478. }
  479. }
  480. }
  481. else
  482. {
  483. color_none:
  484. c = RTGUI_RGB(0, 0, 0);
  485. }
  486. /* add to color hash table */
  487. add_colorhash(colors_table, color_name, colors_pp, &c);
  488. }
  489. /* build rgb pixel data */
  490. image->data = (rt_uint8_t*) rtgui_malloc(image->w * image->h * sizeof(rtgui_color_t));
  491. memset(image->data, 0, image->w * image->h * sizeof(rtgui_color_t));
  492. {
  493. rtgui_color_t *ptr = (rtgui_color_t*) image->data;
  494. for (h = 0; h < image->h; h++)
  495. {
  496. buf = xpm[colors + 1 + h];
  497. for (w = 0; w < image->w; w++, buf += colors_pp)
  498. {
  499. get_colorhash(colors_table, buf, colors_pp, ptr);
  500. ptr ++;
  501. }
  502. }
  503. }
  504. free_colorhash(colors_table);
  505. rtgui_filerw_close(file);
  506. return RT_TRUE;
  507. }
  508. static void rtgui_image_xpm_unload(struct rtgui_image* image)
  509. {
  510. if (image != RT_NULL)
  511. {
  512. /* release data */
  513. rtgui_free(image->data);
  514. image->data = RT_NULL;
  515. }
  516. }
  517. static void rtgui_image_xpm_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* rect)
  518. {
  519. rt_uint16_t x, y;
  520. rtgui_color_t* ptr;
  521. RT_ASSERT(image != RT_NULL && dc != RT_NULL && rect != RT_NULL);
  522. RT_ASSERT(image->data != RT_NULL);
  523. ptr = (rtgui_color_t*) image->data;
  524. /* draw each point within dc */
  525. for (y = 0; y < image->h; y ++)
  526. {
  527. for (x = 0; x < image->w; x++)
  528. {
  529. /* not alpha */
  530. if ((*ptr >> 24) != 255)
  531. {
  532. rtgui_dc_draw_color_point(dc, x + rect->x1, y + rect->y1, *ptr);
  533. }
  534. /* move to next color buffer */
  535. ptr ++;
  536. }
  537. }
  538. }