You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * 2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
  5. * All Rights Reserved
  6. *
  7. * $Id$
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the Do What The Fuck You Want To
  11. * Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains various export functions
  16. */
  17. #include "config.h"
  18. #if !defined(__KERNEL__)
  19. # include <stdlib.h>
  20. # include <stdio.h>
  21. # include <string.h>
  22. #endif
  23. #include "cucul.h"
  24. #include "cucul_internals.h"
  25. static void export_caca(cucul_canvas_t *, cucul_buffer_t *);
  26. static void export_ansi(cucul_canvas_t *, cucul_buffer_t *);
  27. static void export_html(cucul_canvas_t *, cucul_buffer_t *);
  28. static void export_html3(cucul_canvas_t *, cucul_buffer_t *);
  29. static void export_irc(cucul_canvas_t *, cucul_buffer_t *);
  30. static void export_ps(cucul_canvas_t *, cucul_buffer_t *);
  31. static void export_svg(cucul_canvas_t *, cucul_buffer_t *);
  32. static void export_tga(cucul_canvas_t *, cucul_buffer_t *);
  33. /** \brief Export a canvas into a foreign format.
  34. *
  35. * This function exports a libcucul canvas into various foreign formats such
  36. * as ANSI art, HTML, IRC colours, etc. One should use cucul_get_buffer_data()
  37. * and cucul_get_buffer_size() to access the buffer contents. The allocated
  38. * data is valid until cucul_free_buffer() is called.
  39. *
  40. * Valid values for \c format are:
  41. *
  42. * \li \c "caca": export native libcaca files.
  43. *
  44. * \li \c "ansi": export ANSI art (CP437 charset with ANSI colour codes).
  45. *
  46. * \li \c "html": export an HTML page with CSS information.
  47. *
  48. * \li \c "html3": export an HTML table that should be compatible with
  49. * most navigators, including textmode ones.
  50. *
  51. * \li \c "irc": export UTF-8 text with mIRC colour codes.
  52. *
  53. * \li \c "ps": export a PostScript document.
  54. *
  55. * \li \c "svg": export an SVG vector image.
  56. *
  57. * \li \c "tga": export a TGA image.
  58. *
  59. * \param cv A libcucul canvas
  60. * \param format A string describing the requested output format.
  61. */
  62. cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format)
  63. {
  64. cucul_buffer_t *ex;
  65. ex = malloc(sizeof(cucul_buffer_t));
  66. ex->size = 0;
  67. ex->data = NULL;
  68. if(!strcasecmp("caca", format))
  69. export_caca(cv, ex);
  70. else if(!strcasecmp("ansi", format))
  71. export_ansi(cv, ex);
  72. else if(!strcasecmp("html", format))
  73. export_html(cv, ex);
  74. else if(!strcasecmp("html3", format))
  75. export_html3(cv, ex);
  76. else if(!strcasecmp("irc", format))
  77. export_irc(cv, ex);
  78. else if(!strcasecmp("ps", format))
  79. export_ps(cv, ex);
  80. else if(!strcasecmp("svg", format))
  81. export_svg(cv, ex);
  82. else if(!strcasecmp("tga", format))
  83. export_tga(cv, ex);
  84. if(ex->size == 0)
  85. {
  86. free(ex);
  87. return NULL;
  88. }
  89. return ex;
  90. }
  91. /** \brief Get available export formats
  92. *
  93. * Return a list of available export formats. The list is a NULL-terminated
  94. * array of strings, interleaving a string containing the internal value for
  95. * the export format, to be used with cucul_export_canvas(), and a string
  96. * containing the natural language description for that export format.
  97. *
  98. * \return An array of strings.
  99. */
  100. char const * const * cucul_get_export_list(void)
  101. {
  102. static char const * const list[] =
  103. {
  104. "caca", "native libcaca format",
  105. "ansi", "ANSI",
  106. "html", "HTML",
  107. "html3", "backwards-compatible HTML",
  108. "irc", "IRC with mIRC colours",
  109. "ps", "PostScript document",
  110. "svg", "SVG vector image",
  111. "tga", "TGA image",
  112. NULL, NULL
  113. };
  114. return list;
  115. }
  116. /*
  117. * XXX: the following functions are local.
  118. */
  119. /* Generate a native libcaca canvas file. */
  120. static void export_caca(cucul_canvas_t *cv, cucul_buffer_t *ex)
  121. {
  122. uint32_t *attr = cv->attr;
  123. uint32_t *chars = cv->chars;
  124. char *cur;
  125. uint32_t w, h;
  126. unsigned int n;
  127. /* 16 bytes for the canvas, 8 bytes for each character cell. */
  128. ex->size = 16 + 8 * cv->width * cv->height;
  129. ex->data = malloc(ex->size);
  130. cur = ex->data;
  131. w = cv->width;
  132. h = cv->height;
  133. cur += sprintf(cur, "CACACANV%c%c%c%c%c%c%c%c",
  134. (w >> 24), (w >> 16) & 0xff, (w >> 8) & 0xff, w & 0xff,
  135. (h >> 24), (h >> 16) & 0xff, (h >> 8) & 0xff, h & 0xff);
  136. for(n = cv->height * cv->width; n--; )
  137. {
  138. uint32_t ch = *chars++;
  139. uint32_t a = *attr++;
  140. *cur++ = ch >> 24;
  141. *cur++ = (ch >> 16) & 0xff;
  142. *cur++ = (ch >> 8) & 0xff;
  143. *cur++ = ch & 0xff;
  144. *cur++ = a >> 24;
  145. *cur++ = (a >> 16) & 0xff;
  146. *cur++ = (a >> 8) & 0xff;
  147. *cur++ = a & 0xff;
  148. }
  149. }
  150. /* Generate ANSI representation of current canvas. */
  151. static void export_ansi(cucul_canvas_t *cv, cucul_buffer_t *ex)
  152. {
  153. static uint8_t const palette[] =
  154. {
  155. 0, 4, 2, 6, 1, 5, 3, 7,
  156. 8, 12, 10, 14, 9, 13, 11, 15
  157. };
  158. char *cur;
  159. unsigned int x, y;
  160. /* 23 bytes assumed for max length per pixel ('\e[5;1;3x;4y;9x;10ym' plus
  161. * 4 max bytes for a UTF-8 character).
  162. * Add height*9 to that (zeroes color at the end and jump to next line) */
  163. ex->size = (cv->height * 9) + (cv->width * cv->height * 23);
  164. ex->data = malloc(ex->size);
  165. cur = ex->data;
  166. for(y = 0; y < cv->height; y++)
  167. {
  168. uint32_t *lineattr = cv->attr + y * cv->width;
  169. uint32_t *linechar = cv->chars + y * cv->width;
  170. uint8_t prevfg = -1;
  171. uint8_t prevbg = -1;
  172. for(x = 0; x < cv->width; x++)
  173. {
  174. uint8_t fg = palette[_cucul_argb32_to_ansi4fg(lineattr[x])];
  175. uint8_t bg = palette[_cucul_argb32_to_ansi4bg(lineattr[x])];
  176. uint32_t ch = linechar[x];
  177. if(fg != prevfg || bg != prevbg)
  178. {
  179. cur += sprintf(cur, "\033[0;");
  180. if(fg < 8)
  181. if(bg < 8)
  182. cur += sprintf(cur, "3%d;4%dm", fg, bg);
  183. else
  184. cur += sprintf(cur, "5;3%d;4%d;10%dm",
  185. fg, bg - 8, bg - 8);
  186. else
  187. if(bg < 8)
  188. cur += sprintf(cur, "1;3%d;4%d;9%dm",
  189. fg - 8, bg, fg - 8);
  190. else
  191. cur += sprintf(cur, "5;1;3%d;4%d;9%d;10%dm",
  192. fg - 8, bg - 8, fg - 8, bg - 8);
  193. }
  194. *cur++ = ch & 0x7f;
  195. prevfg = fg;
  196. prevbg = bg;
  197. }
  198. cur += sprintf(cur, "\033[0m\r\n");
  199. }
  200. /* Crop to really used size */
  201. ex->size = (uintptr_t)(cur - ex->data);
  202. ex->data = realloc(ex->data, ex->size);
  203. }
  204. /* Generate HTML representation of current canvas. */
  205. static void export_html(cucul_canvas_t *cv, cucul_buffer_t *ex)
  206. {
  207. char *cur;
  208. unsigned int x, y, len;
  209. /* The HTML header: less than 1000 bytes
  210. * A line: 7 chars for "<br />\n"
  211. * A glyph: 47 chars for "<span style="color:#xxx;background-color:#xxx">"
  212. * up to 9 chars for "&#xxxxxx;", far less for pure ASCII
  213. * 7 chars for "</span>" */
  214. ex->size = 1000 + cv->height * (7 + cv->width * (47 + 9 + 7));
  215. ex->data = malloc(ex->size);
  216. cur = ex->data;
  217. /* HTML header */
  218. cur += sprintf(cur, "<html><head>\n");
  219. cur += sprintf(cur, "<title>Generated by libcaca %s</title>\n", VERSION);
  220. cur += sprintf(cur, "</head><body>\n");
  221. cur += sprintf(cur, "<div cellpadding='0' cellspacing='0' style='%s'>\n",
  222. "font-family: monospace, fixed; font-weight: bold;");
  223. for(y = 0; y < cv->height; y++)
  224. {
  225. uint32_t *lineattr = cv->attr + y * cv->width;
  226. uint32_t *linechar = cv->chars + y * cv->width;
  227. for(x = 0; x < cv->width; x += len)
  228. {
  229. cur += sprintf(cur, "<span style=\"color:#%.03x;"
  230. "background-color:#%.03x\">",
  231. _cucul_argb32_to_rgb12fg(lineattr[x]),
  232. _cucul_argb32_to_rgb12bg(lineattr[x]));
  233. for(len = 0;
  234. x + len < cv->width && lineattr[x + len] == lineattr[x];
  235. len++)
  236. {
  237. if(linechar[x + len] <= 0x00000020)
  238. cur += sprintf(cur, "&nbsp;");
  239. else if(linechar[x + len] < 0x00000080)
  240. cur += sprintf(cur, "%c", linechar[x + len]);
  241. else
  242. cur += sprintf(cur, "&#%i;", linechar[x + len]);
  243. }
  244. cur += sprintf(cur, "</span>");
  245. }
  246. /* New line */
  247. cur += sprintf(cur, "<br />\n");
  248. }
  249. cur += sprintf(cur, "</div></body></html>\n");
  250. /* Crop to really used size */
  251. ex->size = strlen(ex->data) + 1;
  252. ex->data = realloc(ex->data, ex->size);
  253. }
  254. /* Export an HTML3 document. This function is way bigger than export_html(),
  255. * but permits viewing in old browsers (or limited ones such as links). It
  256. * will not work under gecko (mozilla rendering engine) unless you set a
  257. * correct header. */
  258. static void export_html3(cucul_canvas_t *cv, cucul_buffer_t *ex)
  259. {
  260. char *cur;
  261. unsigned int x, y, len;
  262. /* The HTML table markup: less than 1000 bytes
  263. * A line: 10 chars for "<tr></tr>\n"
  264. * A glyph: 40 chars for "<td bgcolor=#xxxxxx><font color=#xxxxxx>"
  265. * up to 9 chars for "&#xxxxxx;", far less for pure ASCII
  266. * 12 chars for "</font></td>" */
  267. ex->size = 1000 + cv->height * (10 + cv->width * (40 + 9 + 12));
  268. ex->data = malloc(ex->size);
  269. cur = ex->data;
  270. /* Table */
  271. cur += sprintf(cur, "<table cols='%d' cellpadding='0' cellspacing='0'>\n",
  272. cv->height);
  273. for(y = 0; y < cv->height; y++)
  274. {
  275. uint32_t *lineattr = cv->attr + y * cv->width;
  276. uint32_t *linechar = cv->chars + y * cv->width;
  277. cur += sprintf(cur, "<tr>");
  278. for(x = 0; x < cv->width; x += len)
  279. {
  280. unsigned int i;
  281. /* Use colspan option to factor cells with same attributes
  282. * (see below) */
  283. len = 1;
  284. while(x + len < cv->width && lineattr[x + len] == lineattr[x])
  285. len++;
  286. cur += sprintf(cur, "<td bgcolor=#%.06x",
  287. _cucul_argb32_to_rgb24bg(lineattr[x]));
  288. if(len > 1)
  289. cur += sprintf(cur, " colspan=%d", len);
  290. cur += sprintf(cur, "><font color=#%.06x>",
  291. _cucul_argb32_to_rgb24fg(lineattr[x]));
  292. for(i = 0; i < len; i++)
  293. {
  294. if(linechar[x + i] <= 0x00000020)
  295. cur += sprintf(cur, "&nbsp;");
  296. else if(linechar[x + i] < 0x00000080)
  297. cur += sprintf(cur, "%c", linechar[x + i]);
  298. else
  299. cur += sprintf(cur, "&#%i;", linechar[x + i]);
  300. }
  301. cur += sprintf(cur, "</font></td>");
  302. }
  303. cur += sprintf(cur, "</tr>\n");
  304. }
  305. /* Footer */
  306. cur += sprintf(cur, "</table>\n");
  307. /* Crop to really used size */
  308. ex->size = (uintptr_t)(cur - ex->data);
  309. ex->data = realloc(ex->data, ex->size);
  310. }
  311. /* Export a text file with IRC colours */
  312. static void export_irc(cucul_canvas_t *cv, cucul_buffer_t *ex)
  313. {
  314. static uint8_t const palette[] =
  315. {
  316. 1, 2, 3, 10, 5, 6, 7, 15, /* Dark */
  317. 14, 12, 9, 11, 4, 13, 8, 0, /* Light */
  318. };
  319. char *cur;
  320. unsigned int x, y;
  321. /* 11 bytes assumed for max length per pixel. Worst case scenario:
  322. * ^Cxx,yy 6 bytes
  323. * ^B^B 2 bytes
  324. * ch 1 byte
  325. * \r\n 2 bytes
  326. * In real life, the average bytes per pixel value will be around 5.
  327. */
  328. ex->size = 2 + (cv->width * cv->height * 11);
  329. ex->data = malloc(ex->size);
  330. cur = ex->data;
  331. for(y = 0; y < cv->height; y++)
  332. {
  333. uint32_t *lineattr = cv->attr + y * cv->width;
  334. uint32_t *linechar = cv->chars + y * cv->width;
  335. uint8_t prevfg = -1;
  336. uint8_t prevbg = -1;
  337. for(x = 0; x < cv->width; x++)
  338. {
  339. uint8_t fg = palette[_cucul_argb32_to_ansi4fg(lineattr[x])];
  340. uint8_t bg = palette[_cucul_argb32_to_ansi4bg(lineattr[x])];
  341. uint32_t ch = linechar[x];
  342. if(bg == prevbg)
  343. {
  344. if(fg == prevfg)
  345. ; /* Same fg/bg, do nothing */
  346. else if(ch == (uint32_t)' ')
  347. fg = prevfg; /* Hackety hack */
  348. else
  349. {
  350. cur += sprintf(cur, "\x03%d", fg);
  351. if(ch >= (uint32_t)'0' && ch <= (uint32_t)'9')
  352. cur += sprintf(cur, "\x02\x02");
  353. }
  354. }
  355. else
  356. {
  357. if(fg == prevfg)
  358. cur += sprintf(cur, "\x03,%d", bg);
  359. else
  360. cur += sprintf(cur, "\x03%d,%d", fg, bg);
  361. if(ch >= (uint32_t)'0' && ch <= (uint32_t)'9')
  362. cur += sprintf(cur, "\x02\x02");
  363. }
  364. *cur++ = ch & 0x7f;
  365. prevfg = fg;
  366. prevbg = bg;
  367. }
  368. *cur++ = '\r';
  369. *cur++ = '\n';
  370. }
  371. /* Crop to really used size */
  372. ex->size = (uintptr_t)(cur - ex->data);
  373. ex->data = realloc(ex->data, ex->size);
  374. }
  375. /* Export a PostScript document. */
  376. static void export_ps(cucul_canvas_t *cv, cucul_buffer_t *ex)
  377. {
  378. static char const *ps_header =
  379. "%!\n"
  380. "%% libcaca PDF export\n"
  381. "%%LanguageLevel: 2\n"
  382. "%%Pages: 1\n"
  383. "%%DocumentData: Clean7Bit\n"
  384. "/csquare {\n"
  385. " newpath\n"
  386. " 0 0 moveto\n"
  387. " 0 1 rlineto\n"
  388. " 1 0 rlineto\n"
  389. " 0 -1 rlineto\n"
  390. " closepath\n"
  391. " setrgbcolor\n"
  392. " fill\n"
  393. "} def\n"
  394. "/S {\n"
  395. " Show\n"
  396. "} bind def\n"
  397. "/Courier-Bold findfont\n"
  398. "8 scalefont\n"
  399. "setfont\n"
  400. "gsave\n"
  401. "6 10 scale\n";
  402. char *cur;
  403. unsigned int x, y;
  404. /* 200 is arbitrary but should be ok */
  405. ex->size = strlen(ps_header) + (cv->width * cv->height * 200);
  406. ex->data = malloc(ex->size);
  407. cur = ex->data;
  408. /* Header */
  409. cur += sprintf(cur, "%s", ps_header);
  410. /* Background, drawn using csquare macro defined in header */
  411. for(y = cv->height; y--; )
  412. {
  413. uint32_t *lineattr = cv->attr + y * cv->width;
  414. for(x = 0; x < cv->width; x++)
  415. {
  416. uint8_t argb[8];
  417. _cucul_argb32_to_argb4(*lineattr++, argb);
  418. cur += sprintf(cur, "1 0 translate\n %f %f %f csquare\n",
  419. (float)argb[1] * (1.0 / 0xf),
  420. (float)argb[2] * (1.0 / 0xf),
  421. (float)argb[3] * (1.0 / 0xf));
  422. }
  423. /* Return to beginning of the line, and jump to the next one */
  424. cur += sprintf(cur, "-%d 1 translate\n", cv->width);
  425. }
  426. cur += sprintf(cur, "grestore\n"); /* Restore transformation matrix */
  427. for(y = cv->height; y--; )
  428. {
  429. uint32_t *lineattr = cv->attr + (cv->height - y - 1) * cv->width;
  430. uint32_t *linechar = cv->chars + (cv->height - y - 1) * cv->width;
  431. for(x = 0; x < cv->width; x++)
  432. {
  433. uint8_t argb[8];
  434. uint32_t ch = *linechar++;
  435. _cucul_argb32_to_argb4(*lineattr++, argb);
  436. cur += sprintf(cur, "newpath\n");
  437. cur += sprintf(cur, "%d %d moveto\n", (x + 1) * 6, y * 10 + 2);
  438. cur += sprintf(cur, "%f %f %f setrgbcolor\n",
  439. (float)argb[5] * (1.0 / 0xf),
  440. (float)argb[6] * (1.0 / 0xf),
  441. (float)argb[7] * (1.0 / 0xf));
  442. if(ch < 0x00000020)
  443. cur += sprintf(cur, "(?) show\n");
  444. else if(ch >= 0x00000080)
  445. cur += sprintf(cur, "(?) show\n");
  446. else switch((uint8_t)(ch & 0x7f))
  447. {
  448. case '\\':
  449. case '(':
  450. case ')':
  451. cur += sprintf(cur, "(\\%c) show\n", ch);
  452. break;
  453. default:
  454. cur += sprintf(cur, "(%c) show\n", ch);
  455. break;
  456. }
  457. }
  458. }
  459. cur += sprintf(cur, "showpage\n");
  460. /* Crop to really used size */
  461. ex->size = (uintptr_t)(cur - ex->data);
  462. ex->data = realloc(ex->data, ex->size);
  463. }
  464. /* Export an SVG vector image */
  465. static void export_svg(cucul_canvas_t *cv, cucul_buffer_t *ex)
  466. {
  467. static char const svg_header[] =
  468. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  469. "<svg width=\"%d\" height=\"%d\" viewBox=\"0 0 %d %d\""
  470. " xmlns=\"http://www.w3.org/2000/svg\""
  471. " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
  472. " xml:space=\"preserve\" version=\"1.1\" baseProfile=\"full\">\n";
  473. char *cur;
  474. unsigned int x, y;
  475. /* 200 is arbitrary but should be ok */
  476. ex->size = strlen(svg_header) + (cv->width * cv->height * 200);
  477. ex->data = malloc(ex->size);
  478. cur = ex->data;
  479. /* Header */
  480. cur += sprintf(cur, svg_header, cv->width * 6, cv->height * 10,
  481. cv->width * 6, cv->height * 10);
  482. cur += sprintf(cur, " <g id=\"mainlayer\" font-size=\"12\">\n");
  483. /* Background */
  484. for(y = 0; y < cv->height; y++)
  485. {
  486. uint32_t *lineattr = cv->attr + y * cv->width;
  487. for(x = 0; x < cv->width; x++)
  488. {
  489. cur += sprintf(cur, "<rect style=\"fill:#%.03x\" x=\"%d\" y=\"%d\""
  490. " width=\"6\" height=\"10\"/>\n",
  491. _cucul_argb32_to_rgb12bg(*lineattr++),
  492. x * 6, y * 10);
  493. }
  494. }
  495. /* Text */
  496. for(y = 0; y < cv->height; y++)
  497. {
  498. uint32_t *lineattr = cv->attr + y * cv->width;
  499. uint32_t *linechar = cv->chars + y * cv->width;
  500. for(x = 0; x < cv->width; x++)
  501. {
  502. uint32_t ch = *linechar++;
  503. cur += sprintf(cur, "<text style=\"fill:#%.03x\" "
  504. "x=\"%d\" y=\"%d\">",
  505. _cucul_argb32_to_rgb12fg(*lineattr++),
  506. x * 6, (y * 10) + 10);
  507. if(ch < 0x00000020)
  508. cur += sprintf(cur, "?");
  509. else if(ch > 0x0000007f)
  510. {
  511. static const uint8_t mark[7] =
  512. {
  513. 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
  514. };
  515. char buf[10], *parser;
  516. int bytes = (ch < 0x800) ? 2 : (ch < 0x10000) ? 3 : 4;
  517. buf[bytes] = '\0';
  518. parser = buf + bytes;
  519. switch(bytes)
  520. {
  521. case 4: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
  522. case 3: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
  523. case 2: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
  524. }
  525. *--parser = ch | mark[bytes];
  526. cur += sprintf(cur, "%s", buf);
  527. }
  528. else switch((uint8_t)ch)
  529. {
  530. case '>': cur += sprintf(cur, "&gt;"); break;
  531. case '<': cur += sprintf(cur, "&lt;"); break;
  532. case '&': cur += sprintf(cur, "&amp;"); break;
  533. default: cur += sprintf(cur, "%c", ch); break;
  534. }
  535. cur += sprintf(cur, "</text>\n");
  536. }
  537. }
  538. cur += sprintf(cur, " </g>\n");
  539. cur += sprintf(cur, "</svg>\n");
  540. /* Crop to really used size */
  541. ex->size = (uintptr_t)(cur - ex->data);
  542. ex->data = realloc(ex->data, ex->size);
  543. }
  544. /* Export a TGA image */
  545. static void export_tga(cucul_canvas_t *cv, cucul_buffer_t *ex)
  546. {
  547. char const * const * fontlist;
  548. char * cur;
  549. cucul_font_t *f;
  550. unsigned int i, w, h;
  551. fontlist = cucul_get_font_list();
  552. if(!fontlist[0])
  553. return;
  554. f = cucul_load_font(fontlist[0], 0);
  555. w = cucul_get_canvas_width(cv) * cucul_get_font_width(f);
  556. h = cucul_get_canvas_height(cv) * cucul_get_font_height(f);
  557. ex->size = w * h * 4 + 18; /* 32 bpp + 18 bytes for the header */
  558. ex->data = malloc(ex->size);
  559. cur = ex->data;
  560. /* ID Length */
  561. cur += sprintf(cur, "%c", 0);
  562. /* Color Map Type: no colormap */
  563. cur += sprintf(cur, "%c", 0);
  564. /* Image Type: uncompressed truecolor */
  565. cur += sprintf(cur, "%c", 2);
  566. /* Color Map Specification: no color map */
  567. memset(cur, 0, 5); cur += 5;
  568. /* Image Specification */
  569. cur += sprintf(cur, "%c%c", 0, 0); /* X Origin */
  570. cur += sprintf(cur, "%c%c", 0, 0); /* Y Origin */
  571. cur += sprintf(cur, "%c%c", w & 0xff, w >> 8); /* Width */
  572. cur += sprintf(cur, "%c%c", h & 0xff, h >> 8); /* Height */
  573. cur += sprintf(cur, "%c", 32); /* Pixel Depth */
  574. cur += sprintf(cur, "%c", 40); /* Image Descriptor */
  575. /* Image ID: no ID */
  576. /* Color Map Data: no colormap */
  577. /* Image Data */
  578. cucul_render_canvas(cv, f, cur, w, h, 4 * w);
  579. /* Swap bytes. What a waste of time. */
  580. for(i = 0; i < w * h * 4; i += 4)
  581. {
  582. char w;
  583. w = cur[i]; cur[i] = cur[i + 3]; cur[i + 3] = w;
  584. w = cur[i + 1]; cur[i + 1] = cur[i + 2]; cur[i + 2] = w;
  585. }
  586. cucul_free_font(f);
  587. }