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