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.

пре 15 година
пре 15 година
пре 15 година
пре 15 година
пре 15 година
пре 15 година
пре 15 година
пре 18 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. /*
  2. * libcaca Colour ASCII-Art library
  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. It comes without any warranty, to
  10. * the extent permitted by applicable law. You can redistribute it
  11. * and/or modify it under the terms of the Do What The Fuck You Want
  12. * To Public License, Version 2, as published by Sam Hocevar. See
  13. * http://sam.zoy.org/wtfpl/COPYING for more details.
  14. */
  15. /*
  16. * This file contains various export functions
  17. */
  18. #include "config.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdlib.h>
  21. # include <stdio.h>
  22. # include <string.h>
  23. #endif
  24. #include "caca.h"
  25. #include "caca_internals.h"
  26. static inline int sprintu32(char *s, uint32_t x)
  27. {
  28. s[0] = (uint8_t)(x >> 24);
  29. s[1] = (uint8_t)(x >> 16) & 0xff;
  30. s[2] = (uint8_t)(x >> 8) & 0xff;
  31. s[3] = (uint8_t)(x ) & 0xff;
  32. return 4;
  33. }
  34. static inline int sprintu16(char *s, uint16_t x)
  35. {
  36. s[0] = (uint8_t)(x >> 8) & 0xff;
  37. s[1] = (uint8_t)(x ) & 0xff;
  38. return 2;
  39. }
  40. static void *export_caca(caca_canvas_t const *, size_t *);
  41. static void *export_ansi(caca_canvas_t const *, size_t *);
  42. static void *export_utf8(caca_canvas_t const *, size_t *, int);
  43. static void *export_html(caca_canvas_t const *, size_t *);
  44. static void *export_html3(caca_canvas_t const *, size_t *);
  45. static void *export_bbfr(caca_canvas_t const *, size_t *);
  46. static void *export_irc(caca_canvas_t const *, size_t *);
  47. static void *export_ps(caca_canvas_t const *, size_t *);
  48. static void *export_svg(caca_canvas_t const *, size_t *);
  49. static void *export_tga(caca_canvas_t const *, size_t *);
  50. /** \brief Export a canvas into a foreign format.
  51. *
  52. * This function exports a libcaca canvas into various foreign formats such
  53. * as ANSI art, HTML, IRC colours, etc. The returned pointer should be passed
  54. * to free() to release the allocated storage when it is no longer needed.
  55. *
  56. * Valid values for \c format are:
  57. * - \c "caca": export native libcaca files.
  58. * - \c "ansi": export ANSI art (CP437 charset with ANSI colour codes).
  59. * - \c "html": export an HTML page with CSS information.
  60. * - \c "html3": export an HTML table that should be compatible with
  61. * most navigators, including textmode ones.
  62. * - \c "irc": export UTF-8 text with mIRC colour codes.
  63. * - \c "ps": export a PostScript document.
  64. * - \c "svg": export an SVG vector image.
  65. * - \c "tga": export a TGA image.
  66. *
  67. * If an error occurs, NULL is returned and \b errno is set accordingly:
  68. * - \c EINVAL Unsupported format requested.
  69. * - \c ENOMEM Not enough memory to allocate output buffer.
  70. *
  71. * \param cv A libcaca canvas
  72. * \param format A string describing the requested output format.
  73. * \param bytes A pointer to a size_t where the number of allocated bytes
  74. * will be written.
  75. * \return A pointer to the exported memory area, or NULL in case of error.
  76. */
  77. void *caca_export_memory(caca_canvas_t const *cv, char const *format,
  78. size_t *bytes)
  79. {
  80. if(!strcasecmp("caca", format))
  81. return export_caca(cv, bytes);
  82. if(!strcasecmp("ansi", format))
  83. return export_ansi(cv, bytes);
  84. if(!strcasecmp("utf8", format))
  85. return export_utf8(cv, bytes, 0);
  86. if(!strcasecmp("utf8cr", format))
  87. return export_utf8(cv, bytes, 1);
  88. if(!strcasecmp("html", format))
  89. return export_html(cv, bytes);
  90. if(!strcasecmp("html3", format))
  91. return export_html3(cv, bytes);
  92. if(!strcasecmp("bbfr", format))
  93. return export_bbfr(cv, bytes);
  94. if(!strcasecmp("irc", format))
  95. return export_irc(cv, bytes);
  96. if(!strcasecmp("ps", format))
  97. return export_ps(cv, bytes);
  98. if(!strcasecmp("svg", format))
  99. return export_svg(cv, bytes);
  100. if(!strcasecmp("tga", format))
  101. return export_tga(cv, bytes);
  102. seterrno(EINVAL);
  103. return NULL;
  104. }
  105. /** \brief Get available export formats
  106. *
  107. * Return a list of available export formats. The list is a NULL-terminated
  108. * array of strings, interleaving a string containing the internal value for
  109. * the export format, to be used with caca_export_memory(), and a string
  110. * containing the natural language description for that export format.
  111. *
  112. * This function never fails.
  113. *
  114. * \return An array of strings.
  115. */
  116. char const * const * caca_get_export_list(void)
  117. {
  118. static char const * const list[] =
  119. {
  120. "caca", "native libcaca format",
  121. "ansi", "ANSI",
  122. "utf8", "UTF-8 with ANSI escape codes",
  123. "utf8cr", "UTF-8 with ANSI escape codes and MS-DOS \\r",
  124. "html", "HTML",
  125. "html3", "backwards-compatible HTML",
  126. "bbfr", "BBCode (French)",
  127. "irc", "IRC with mIRC colours",
  128. "ps", "PostScript document",
  129. "svg", "SVG vector image",
  130. "tga", "TGA image",
  131. NULL, NULL
  132. };
  133. return list;
  134. }
  135. /*
  136. * XXX: the following functions are local.
  137. */
  138. /* Generate a native libcaca canvas file. */
  139. static void *export_caca(caca_canvas_t const *cv, size_t *bytes)
  140. {
  141. char *data, *cur;
  142. int f, i, n;
  143. /* at least 72 bytes for the header:
  144. * - 4 bytes for "\xCA\xCA" + "CV"
  145. * - 20 bytes for the canvas header
  146. * - 16 bytes for each dirty rectangle info
  147. * - 32 bytes for each frame info
  148. * 8 bytes for each character cell */
  149. *bytes = 24 + 16 * cv->ndirty + (32 + 8 * cv->width * cv->height) * cv->framecount;
  150. cur = data = malloc(*bytes);
  151. /* magic */
  152. cur += sprintf(cur, "%s", "\xCA\xCA" "CV");
  153. /* canvas_header */
  154. cur += sprintu32(cur, 20 + 16 * cv->ndirty + 32 * cv->framecount);
  155. cur += sprintu32(cur, cv->width * cv->height * 8 * cv->framecount);
  156. cur += sprintu16(cur, 0x0002);
  157. cur += sprintu32(cur, cv->ndirty);
  158. cur += sprintu32(cur, cv->framecount);
  159. cur += sprintu16(cur, 0x0000);
  160. /* dirty rectangles info */
  161. for(i = 0; i < cv->ndirty; i++)
  162. {
  163. cur += sprintu32(cur, cv->dirty_xmin);
  164. cur += sprintu32(cur, cv->dirty_ymin);
  165. cur += sprintu32(cur, cv->dirty_xmax);
  166. cur += sprintu32(cur, cv->dirty_ymax);
  167. }
  168. /* frame_info */
  169. for(f = 0; f < cv->framecount; f++)
  170. {
  171. cur += sprintu32(cur, cv->width);
  172. cur += sprintu32(cur, cv->height);
  173. cur += sprintu32(cur, 0);
  174. cur += sprintu32(cur, cv->curattr);
  175. cur += sprintu32(cur, cv->frames[f].x);
  176. cur += sprintu32(cur, cv->frames[f].y);
  177. cur += sprintu32(cur, cv->frames[f].handlex);
  178. cur += sprintu32(cur, cv->frames[f].handley);
  179. }
  180. /* canvas_data */
  181. for(f = 0; f < cv->framecount; f++)
  182. {
  183. uint32_t *attrs = cv->frames[f].attrs;
  184. uint32_t *chars = cv->frames[f].chars;
  185. for(n = cv->height * cv->width; n--; )
  186. {
  187. cur += sprintu32(cur, *chars++);
  188. cur += sprintu32(cur, *attrs++);
  189. }
  190. }
  191. return data;
  192. }
  193. /* Generate UTF-8 representation of current canvas. */
  194. static void *export_utf8(caca_canvas_t const *cv, size_t *bytes,
  195. int cr)
  196. {
  197. static uint8_t const palette[] =
  198. {
  199. 0, 4, 2, 6, 1, 5, 3, 7,
  200. 8, 12, 10, 14, 9, 13, 11, 15
  201. };
  202. char *data, *cur;
  203. int x, y;
  204. /* 23 bytes assumed for max length per pixel ('\e[5;1;3x;4y;9x;10ym' plus
  205. * 4 max bytes for a UTF-8 character).
  206. * Add height*9 to that (zeroes color at the end and jump to next line) */
  207. *bytes = (cv->height * 9) + (cv->width * cv->height * 23);
  208. cur = data = malloc(*bytes);
  209. for(y = 0; y < cv->height; y++)
  210. {
  211. uint32_t *lineattr = cv->attrs + y * cv->width;
  212. uint32_t *linechar = cv->chars + y * cv->width;
  213. uint8_t prevfg = 0x10;
  214. uint8_t prevbg = 0x10;
  215. for(x = 0; x < cv->width; x++)
  216. {
  217. uint32_t attr = lineattr[x];
  218. uint32_t ch = linechar[x];
  219. uint8_t ansifg, ansibg, fg, bg;
  220. if(ch == CACA_MAGIC_FULLWIDTH)
  221. continue;
  222. ansifg = caca_attr_to_ansi_fg(attr);
  223. ansibg = caca_attr_to_ansi_bg(attr);
  224. fg = ansifg < 0x10 ? palette[ansifg] : 0x10;
  225. bg = ansibg < 0x10 ? palette[ansibg] : 0x10;
  226. /* TODO: the [0 could be omitted in some cases */
  227. if(fg != prevfg || bg != prevbg)
  228. {
  229. cur += sprintf(cur, "\033[0");
  230. if(fg < 8)
  231. cur += sprintf(cur, ";3%d", fg);
  232. else if(fg < 16)
  233. cur += sprintf(cur, ";1;3%d;9%d", fg - 8, fg - 8);
  234. if(bg < 8)
  235. cur += sprintf(cur, ";4%d", bg);
  236. else if(bg < 16)
  237. cur += sprintf(cur, ";5;4%d;10%d", bg - 8, bg - 8);
  238. cur += sprintf(cur, "m");
  239. }
  240. cur += caca_utf32_to_utf8(cur, ch);
  241. prevfg = fg;
  242. prevbg = bg;
  243. }
  244. if(prevfg != 0x10 || prevbg != 0x10)
  245. cur += sprintf(cur, "\033[0m");
  246. cur += sprintf(cur, cr ? "\r\n" : "\n");
  247. }
  248. /* Crop to really used size */
  249. debug("utf8 export: alloc %lu bytes, realloc %lu",
  250. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  251. *bytes = (uintptr_t)(cur - data);
  252. data = realloc(data, *bytes);
  253. return data;
  254. }
  255. /* Generate ANSI representation of current canvas. */
  256. static void *export_ansi(caca_canvas_t const *cv, size_t *bytes)
  257. {
  258. static uint8_t const palette[] =
  259. {
  260. 0, 4, 2, 6, 1, 5, 3, 7,
  261. 8, 12, 10, 14, 9, 13, 11, 15
  262. };
  263. char *data, *cur;
  264. int x, y;
  265. uint8_t prevfg = -1;
  266. uint8_t prevbg = -1;
  267. /* 16 bytes assumed for max length per pixel ('\e[5;1;3x;4ym' plus
  268. * 1 byte for a CP437 character).
  269. * Add height*9 to that (zeroes color at the end and jump to next line) */
  270. *bytes = (cv->height * 9) + (cv->width * cv->height * 16);
  271. cur = data = malloc(*bytes);
  272. for(y = 0; y < cv->height; y++)
  273. {
  274. uint32_t *lineattr = cv->attrs + y * cv->width;
  275. uint32_t *linechar = cv->chars + y * cv->width;
  276. for(x = 0; x < cv->width; x++)
  277. {
  278. uint8_t ansifg = caca_attr_to_ansi_fg(lineattr[x]);
  279. uint8_t ansibg = caca_attr_to_ansi_bg(lineattr[x]);
  280. uint8_t fg = ansifg < 0x10 ? palette[ansifg] : CACA_LIGHTGRAY;
  281. uint8_t bg = ansibg < 0x10 ? palette[ansibg] : CACA_BLACK;
  282. uint32_t ch = linechar[x];
  283. if(ch == CACA_MAGIC_FULLWIDTH)
  284. ch = '?';
  285. if(fg != prevfg || bg != prevbg)
  286. {
  287. cur += sprintf(cur, "\033[0;");
  288. if(fg < 8)
  289. if(bg < 8)
  290. cur += sprintf(cur, "3%d;4%dm", fg, bg);
  291. else
  292. cur += sprintf(cur, "5;3%d;4%dm", fg, bg - 8);
  293. else
  294. if(bg < 8)
  295. cur += sprintf(cur, "1;3%d;4%dm", fg - 8, bg);
  296. else
  297. cur += sprintf(cur, "5;1;3%d;4%dm", fg - 8, bg - 8);
  298. }
  299. *cur++ = caca_utf32_to_cp437(ch);
  300. prevfg = fg;
  301. prevbg = bg;
  302. }
  303. if(cv->width == 80)
  304. {
  305. cur += sprintf(cur, "\033[s\n\033[u");
  306. }
  307. else
  308. {
  309. cur += sprintf(cur, "\033[0m\r\n");
  310. prevfg = -1;
  311. prevbg = -1;
  312. }
  313. }
  314. /* Crop to really used size */
  315. debug("ansi export: alloc %lu bytes, realloc %lu",
  316. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  317. *bytes = (uintptr_t)(cur - data);
  318. data = realloc(data, *bytes);
  319. return data;
  320. }
  321. /* Generate HTML representation of current canvas. */
  322. static void *export_html(caca_canvas_t const *cv, size_t *bytes)
  323. {
  324. char *data, *cur;
  325. int x, y, len;
  326. /* The HTML header: less than 1000 bytes
  327. * A line: 7 chars for "<br />\n"
  328. * A glyph: 47 chars for "<span style="color:#xxx;background-color:#xxx">"
  329. * 83 chars for ";font-weight..."
  330. * up to 10 chars for "&#xxxxxxx;", far less for pure ASCII
  331. * 7 chars for "</span>" */
  332. *bytes = 1000 + cv->height * (7 + cv->width * (47 + 83 + 10 + 7));
  333. cur = data = malloc(*bytes);
  334. /* HTML header */
  335. cur += sprintf(cur, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n");
  336. cur += sprintf(cur, " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
  337. cur += sprintf(cur, "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">");
  338. cur += sprintf(cur, "<head>\n");
  339. cur += sprintf(cur, "<title>Generated by libcaca %s</title>\n",
  340. caca_get_version());
  341. cur += sprintf(cur, "</head><body>\n");
  342. cur += sprintf(cur, "<div style=\"%s\">\n",
  343. "font-family: monospace, fixed; font-weight: bold;");
  344. for(y = 0; y < cv->height; y++)
  345. {
  346. uint32_t *lineattr = cv->attrs + y * cv->width;
  347. uint32_t *linechar = cv->chars + y * cv->width;
  348. for(x = 0; x < cv->width; x += len)
  349. {
  350. cur += sprintf(cur, "<span style=\"");
  351. if(caca_attr_to_ansi_fg(lineattr[x]) != CACA_DEFAULT)
  352. cur += sprintf(cur, ";color:#%.03x",
  353. caca_attr_to_rgb12_fg(lineattr[x]));
  354. if(caca_attr_to_ansi_bg(lineattr[x]) < 0x10)
  355. cur += sprintf(cur, ";background-color:#%.03x",
  356. caca_attr_to_rgb12_bg(lineattr[x]));
  357. if(lineattr[x] & CACA_BOLD)
  358. cur += sprintf(cur, ";font-weight:bold");
  359. if(lineattr[x] & CACA_ITALICS)
  360. cur += sprintf(cur, ";font-style:italic");
  361. if(lineattr[x] & CACA_UNDERLINE)
  362. cur += sprintf(cur, ";text-decoration:underline");
  363. if(lineattr[x] & CACA_BLINK)
  364. cur += sprintf(cur, ";text-decoration:blink");
  365. cur += sprintf(cur, "\">");
  366. for(len = 0;
  367. x + len < cv->width && lineattr[x + len] == lineattr[x];
  368. len++)
  369. {
  370. if(linechar[x + len] == CACA_MAGIC_FULLWIDTH)
  371. ;
  372. else if((linechar[x + len] <= 0x00000020)
  373. ||
  374. ((linechar[x + len] >= 0x0000007f)
  375. &&
  376. (linechar[x + len] <= 0x000000a0)))
  377. {
  378. /* Control characters and space converted to
  379. * U+00A0 NO-BREAK SPACE, a.k.a. "&nbsp;" in HTML,
  380. * but we use the equivalent numeric character
  381. * reference &#160; so this will work in plain
  382. * XHTML with no DTD too. */
  383. cur += sprintf(cur, "&#160;");
  384. }
  385. else if(linechar[x + len] == '&')
  386. cur += sprintf(cur, "&amp;");
  387. else if(linechar[x + len] == '<')
  388. cur += sprintf(cur, "&lt;");
  389. else if(linechar[x + len] == '>')
  390. cur += sprintf(cur, "&gt;");
  391. else if(linechar[x + len] == '\"')
  392. cur += sprintf(cur, "&quot;");
  393. else if(linechar[x + len] == '\'')
  394. cur += sprintf(cur, "&#39;");
  395. else if(linechar[x + len] < 0x00000080)
  396. cur += sprintf(cur, "%c", (uint8_t)linechar[x + len]);
  397. else if((linechar[x + len] <= 0x0010fffd)
  398. &&
  399. ((linechar[x + len] & 0x0000fffe) != 0x0000fffe)
  400. &&
  401. ((linechar[x + len] < 0x0000d800)
  402. ||
  403. (linechar[x + len] > 0x0000dfff)))
  404. cur += sprintf(cur, "&#%i;", (unsigned int)linechar[x + len]);
  405. else
  406. /* non-character codepoints become U+FFFD
  407. * REPLACEMENT CHARACTER */
  408. cur += sprintf(cur, "&#%i;", (unsigned int)0x0000fffd);
  409. }
  410. cur += sprintf(cur, "</span>");
  411. }
  412. /* New line */
  413. cur += sprintf(cur, "<br />\n");
  414. }
  415. cur += sprintf(cur, "</div></body></html>\n");
  416. /* Crop to really used size */
  417. debug("html export: alloc %lu bytes, realloc %lu",
  418. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  419. *bytes = (uintptr_t)(cur - data);
  420. data = realloc(data, *bytes);
  421. return data;
  422. }
  423. /* Export an HTML3 document. This function is way bigger than export_html(),
  424. * but permits viewing in old browsers (or limited ones such as links). It
  425. * will not work under gecko (mozilla rendering engine) unless you set a
  426. * correct header. */
  427. static void *export_html3(caca_canvas_t const *cv, size_t *bytes)
  428. {
  429. char *data, *cur;
  430. int x, y, len;
  431. int has_multi_cell_row = 0;
  432. unsigned char *cell_boundary_bitmap;
  433. /* Table */
  434. cell_boundary_bitmap = (unsigned char *) malloc((cv->width + 7) / 8);
  435. if(cell_boundary_bitmap)
  436. memset((void *) cell_boundary_bitmap, 0, (cv->width + 7) / 8);
  437. for(y = 0; y < cv->height; y++)
  438. {
  439. uint32_t *lineattr = cv->attrs + y * cv->width;
  440. uint32_t *linechar = cv->chars + y * cv->width;
  441. for(x = 1; x < cv->width; x++)
  442. if((! (cell_boundary_bitmap
  443. ?
  444. (cell_boundary_bitmap[x / 8] & (1 << (x % 8)))
  445. :
  446. has_multi_cell_row))
  447. &&
  448. (((linechar[x - 1] == CACA_MAGIC_FULLWIDTH)
  449. &&
  450. (! caca_utf32_is_fullwidth(linechar[x])))
  451. ||
  452. (caca_attr_to_ansi_bg(lineattr[x - 1])
  453. !=
  454. caca_attr_to_ansi_bg(lineattr[x]))
  455. ||
  456. ((caca_attr_to_ansi_bg(lineattr[x]) < 0x10)
  457. ?
  458. (_caca_attr_to_rgb24bg(lineattr[x - 1])
  459. !=
  460. _caca_attr_to_rgb24bg(lineattr[x]))
  461. :
  462. 0)))
  463. {
  464. has_multi_cell_row = 1;
  465. if(cell_boundary_bitmap)
  466. cell_boundary_bitmap[x / 8] |= 1 << (x % 8);
  467. }
  468. }
  469. /* The HTML table markup: less than 1000 bytes
  470. * A line: 10 chars for "<tr></tr>\n"
  471. * A glyph: up to 48 chars for "<td bgcolor=\"#xxxxxx\"><tt><font color=\"#xxxxxx\">"
  472. * up to 36 chars for "<b><i><u><blink></blink></u></i></b>"
  473. * up to 10 chars for "&#xxxxxxx;" (far less for pure ASCII)
  474. * 17 chars for "</font></tt></td>" */
  475. *bytes = 1000 + cv->height * (10 + cv->width * (48 + 36 + 10 + 17));
  476. cur = data = malloc(*bytes);
  477. cur += sprintf(cur, "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" summary=\"[libcaca canvas export]\">\n");
  478. for(y = 0; y < cv->height; y++)
  479. {
  480. uint32_t *lineattr = cv->attrs + y * cv->width;
  481. uint32_t *linechar = cv->chars + y * cv->width;
  482. cur += sprintf(cur, "<tr>");
  483. for(x = 0; x < cv->width; x += len)
  484. {
  485. int i, needfont = 0;
  486. int nonblank = 0;
  487. /* Use colspan option to factor cells with same attributes
  488. * (see below) */
  489. len = 1;
  490. while((x + len < cv->width)
  491. &&
  492. ((y
  493. &&
  494. (linechar[x + len] > 0x00000020)
  495. &&
  496. ((linechar[x + len] < 0x0000007f)
  497. ||
  498. (linechar[x + len] > 0x000000a0)))
  499. ||
  500. (! (cell_boundary_bitmap
  501. ?
  502. (cell_boundary_bitmap[(x + len) / 8] & (1 << ((x + len) % 8)))
  503. :
  504. has_multi_cell_row))
  505. ||
  506. (linechar[x + len] == CACA_MAGIC_FULLWIDTH)
  507. ||
  508. (cv->height == 1))
  509. &&
  510. ((linechar[x + len - 1] != CACA_MAGIC_FULLWIDTH)
  511. ||
  512. caca_utf32_is_fullwidth(linechar[x + len]))
  513. &&
  514. (caca_attr_to_ansi_bg(lineattr[x + len])
  515. ==
  516. caca_attr_to_ansi_bg(lineattr[x]))
  517. &&
  518. ((caca_attr_to_ansi_bg(lineattr[x]) < 0x10)
  519. ?
  520. (_caca_attr_to_rgb24bg(lineattr[x + len])
  521. ==
  522. _caca_attr_to_rgb24bg(lineattr[x]))
  523. :
  524. 1))
  525. len++;
  526. for(i = 0; i < len; i++)
  527. if(! ((linechar[x + i] <= 0x00000020)
  528. ||
  529. ((linechar[x + i] >= 0x0000007f)
  530. &&
  531. (linechar[x + i] <= 0x000000a0))))
  532. nonblank = 1;
  533. cur += sprintf(cur, "<td");
  534. if(caca_attr_to_ansi_bg(lineattr[x]) < 0x10)
  535. cur += sprintf(cur, " bgcolor=\"#%.06lx\"", (unsigned long int)
  536. _caca_attr_to_rgb24bg(lineattr[x]));
  537. if(has_multi_cell_row && (len > 1))
  538. {
  539. int colspan;
  540. colspan = len;
  541. if(cell_boundary_bitmap)
  542. for(i = 0; i < len; i ++)
  543. if(i
  544. &&
  545. ! (cell_boundary_bitmap[(x + i) / 8]
  546. &
  547. (1 << ((x + i) % 8))))
  548. colspan --;
  549. if(colspan > 1)
  550. cur += sprintf(cur, " colspan=\"%d\"", colspan);
  551. }
  552. cur += sprintf(cur, ">");
  553. cur += sprintf(cur, "<tt>");
  554. for(i = 0; i < len; i++)
  555. {
  556. if(nonblank
  557. &&
  558. ((! i)
  559. ||
  560. (lineattr[x + i] != lineattr[x + i - 1])))
  561. {
  562. needfont = (caca_attr_to_ansi_fg(lineattr[x + i])
  563. !=
  564. CACA_DEFAULT);
  565. if(needfont)
  566. cur += sprintf(cur, "<font color=\"#%.06lx\">",
  567. (unsigned long int)
  568. _caca_attr_to_rgb24fg(lineattr[x + i]));
  569. if(lineattr[x + i] & CACA_BOLD)
  570. cur += sprintf(cur, "<b>");
  571. if(lineattr[x + i] & CACA_ITALICS)
  572. cur += sprintf(cur, "<i>");
  573. if(lineattr[x + i] & CACA_UNDERLINE)
  574. cur += sprintf(cur, "<u>");
  575. if(lineattr[x + i] & CACA_BLINK)
  576. cur += sprintf(cur, "<blink>");
  577. }
  578. if(linechar[x + i] == CACA_MAGIC_FULLWIDTH)
  579. ;
  580. else if((linechar[x + i] <= 0x00000020)
  581. ||
  582. ((linechar[x + i] >= 0x0000007f)
  583. &&
  584. (linechar[x + i] <= 0x000000a0)))
  585. {
  586. /* Control characters and space converted to
  587. * U+00A0 NO-BREAK SPACE, a.k.a. "&nbsp;" in HTML,
  588. * but we use the equivalent numeric character
  589. * reference &#160; so this will work in plain
  590. * XHTML with no DTD too. */
  591. cur += sprintf(cur, "&#160;");
  592. }
  593. else if(linechar[x + i] == '&')
  594. cur += sprintf(cur, "&amp;");
  595. else if(linechar[x + i] == '<')
  596. cur += sprintf(cur, "&lt;");
  597. else if(linechar[x + i] == '>')
  598. cur += sprintf(cur, "&gt;");
  599. else if(linechar[x + i] == '\"')
  600. cur += sprintf(cur, "&quot;");
  601. else if(linechar[x + i] == '\'')
  602. cur += sprintf(cur, "&#39;");
  603. else if(linechar[x + i] < 0x00000080)
  604. cur += sprintf(cur, "%c", (uint8_t)linechar[x + i]);
  605. else if((linechar[x + i] <= 0x0010fffd)
  606. &&
  607. ((linechar[x + i] & 0x0000fffe) != 0x0000fffe)
  608. &&
  609. ((linechar[x + i] < 0x0000d800)
  610. ||
  611. (linechar[x + i] > 0x0000dfff)))
  612. cur += sprintf(cur, "&#%i;", (unsigned int)linechar[x + i]);
  613. else
  614. /* non-character codepoints become U+FFFD
  615. * REPLACEMENT CHARACTER */
  616. cur += sprintf(cur, "&#%i;", (unsigned int)0x0000fffd);
  617. if (nonblank
  618. &&
  619. (((i + 1) == len)
  620. ||
  621. (lineattr[x + i + 1] != lineattr[x + i])))
  622. {
  623. if(lineattr[x + i] & CACA_BLINK)
  624. cur += sprintf(cur, "</blink>");
  625. if(lineattr[x + i] & CACA_UNDERLINE)
  626. cur += sprintf(cur, "</u>");
  627. if(lineattr[x + i] & CACA_ITALICS)
  628. cur += sprintf(cur, "</i>");
  629. if(lineattr[x + i] & CACA_BOLD)
  630. cur += sprintf(cur, "</b>");
  631. if(needfont)
  632. cur += sprintf(cur, "</font>");
  633. }
  634. }
  635. cur += sprintf(cur, "</tt>");
  636. cur += sprintf(cur, "</td>");
  637. }
  638. cur += sprintf(cur, "</tr>\n");
  639. }
  640. /* Footer */
  641. cur += sprintf(cur, "</table>\n");
  642. /* Free working memory */
  643. if (cell_boundary_bitmap)
  644. free((void *) cell_boundary_bitmap);
  645. /* Crop to really used size */
  646. debug("html3 export: alloc %lu bytes, realloc %lu",
  647. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  648. *bytes = (uintptr_t)(cur - data);
  649. data = realloc(data, *bytes);
  650. return data;
  651. }
  652. static void *export_bbfr(caca_canvas_t const *cv, size_t *bytes)
  653. {
  654. char *data, *cur;
  655. int x, y, len;
  656. /* The font markup: less than 100 bytes
  657. * A line: 1 char for "\n"
  658. * A glyph: 22 chars for "[f=#xxxxxx][c=#xxxxxx]"
  659. * up to 21 chars for "[g][i][s][/s][/i][/g]"
  660. * up to 6 chars for the UTF-8 glyph
  661. * 8 chars for "[/c][/f]" */
  662. *bytes = 100 + cv->height * (1 + cv->width * (22 + 21 + 6 + 8));
  663. cur = data = malloc(*bytes);
  664. /* Table */
  665. cur += sprintf(cur, "[font=Courier New]");
  666. for(y = 0; y < cv->height; y++)
  667. {
  668. uint32_t *lineattr = cv->attrs + y * cv->width;
  669. uint32_t *linechar = cv->chars + y * cv->width;
  670. for(x = 0; x < cv->width; x += len)
  671. {
  672. int i, needback, needfront;
  673. /* Use colspan option to factor cells with same attributes
  674. * (see below) */
  675. len = 1;
  676. if(linechar[x] == ' ')
  677. while(x + len < cv->width && lineattr[x + len] == lineattr[x]
  678. && linechar[x] == ' ')
  679. len++;
  680. else
  681. while(x + len < cv->width && lineattr[x + len] == lineattr[x]
  682. && linechar[x] != ' ')
  683. len++;
  684. needback = caca_attr_to_ansi_bg(lineattr[x]) < 0x10;
  685. needfront = caca_attr_to_ansi_fg(lineattr[x]) < 0x10;
  686. if(needback)
  687. cur += sprintf(cur, "[f=#%.06lx]", (unsigned long int)
  688. _caca_attr_to_rgb24bg(lineattr[x]));
  689. if(linechar[x] == ' ')
  690. cur += sprintf(cur, "[c=#%.06lx]", (unsigned long int)
  691. _caca_attr_to_rgb24bg(lineattr[x]));
  692. else if(needfront)
  693. cur += sprintf(cur, "[c=#%.06lx]", (unsigned long int)
  694. _caca_attr_to_rgb24fg(lineattr[x]));
  695. if(lineattr[x] & CACA_BOLD)
  696. cur += sprintf(cur, "[g]");
  697. if(lineattr[x] & CACA_ITALICS)
  698. cur += sprintf(cur, "[i]");
  699. if(lineattr[x] & CACA_UNDERLINE)
  700. cur += sprintf(cur, "[s]");
  701. if(lineattr[x] & CACA_BLINK)
  702. ; /* FIXME */
  703. for(i = 0; i < len; i++)
  704. {
  705. if(linechar[x + i] == CACA_MAGIC_FULLWIDTH)
  706. ;
  707. else if(linechar[x + i] == ' ')
  708. *cur++ = '_';
  709. else
  710. cur += caca_utf32_to_utf8(cur, linechar[x + i]);
  711. }
  712. if(lineattr[x] & CACA_BLINK)
  713. ; /* FIXME */
  714. if(lineattr[x] & CACA_UNDERLINE)
  715. cur += sprintf(cur, "[/s]");
  716. if(lineattr[x] & CACA_ITALICS)
  717. cur += sprintf(cur, "[/i]");
  718. if(lineattr[x] & CACA_BOLD)
  719. cur += sprintf(cur, "[/g]");
  720. if(linechar[x] == ' ' || needfront)
  721. cur += sprintf(cur, "[/c]");
  722. if(needback)
  723. cur += sprintf(cur, "[/f]");
  724. }
  725. cur += sprintf(cur, "\n");
  726. }
  727. /* Footer */
  728. cur += sprintf(cur, "[/font]\n");
  729. /* Crop to really used size */
  730. debug("bbfr export: alloc %lu bytes, realloc %lu",
  731. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  732. *bytes = (uintptr_t)(cur - data);
  733. data = realloc(data, *bytes);
  734. return data;
  735. }
  736. /* Export a text file with IRC colours */
  737. static void *export_irc(caca_canvas_t const *cv, size_t *bytes)
  738. {
  739. static uint8_t const palette[] =
  740. {
  741. 1, 2, 3, 10, 5, 6, 7, 15, /* Dark */
  742. 14, 12, 9, 11, 4, 13, 8, 0, /* Light */
  743. };
  744. char *data, *cur;
  745. int x, y;
  746. /* 14 bytes assumed for max length per pixel. Worst case scenario:
  747. * ^Cxx,yy 6 bytes
  748. * ^B^B 2 bytes
  749. * ch 6 bytes
  750. * 3 bytes for max length per line. Worst case scenario:
  751. * <spc> 1 byte (for empty lines)
  752. * \r\n 2 bytes
  753. * In real life, the average bytes per pixel value will be around 5.
  754. */
  755. *bytes = 2 + cv->height * (3 + cv->width * 14);
  756. cur = data = malloc(*bytes);
  757. for(y = 0; y < cv->height; y++)
  758. {
  759. uint32_t *lineattr = cv->attrs + y * cv->width;
  760. uint32_t *linechar = cv->chars + y * cv->width;
  761. uint8_t prevfg = 0x10;
  762. uint8_t prevbg = 0x10;
  763. for(x = 0; x < cv->width; x++)
  764. {
  765. uint32_t attr = lineattr[x];
  766. uint32_t ch = linechar[x];
  767. uint8_t ansifg, ansibg, fg, bg;
  768. if(ch == CACA_MAGIC_FULLWIDTH)
  769. continue;
  770. ansifg = caca_attr_to_ansi_fg(attr);
  771. ansibg = caca_attr_to_ansi_bg(attr);
  772. fg = ansifg < 0x10 ? palette[ansifg] : 0x10;
  773. bg = ansibg < 0x10 ? palette[ansibg] : 0x10;
  774. /* TODO: optimise series of same fg / same bg
  775. * don't change fg value if ch == ' '
  776. * make sure the \x03,%d trick works everywhere */
  777. if(bg != prevbg || fg != prevfg)
  778. {
  779. int need_escape = 0;
  780. if(bg == 0x10)
  781. {
  782. if(fg == 0x10)
  783. cur += sprintf(cur, "\x0f");
  784. else
  785. {
  786. if(prevbg == 0x10)
  787. cur += sprintf(cur, "\x03%d", fg);
  788. else
  789. cur += sprintf(cur, "\x0f\x03%d", fg);
  790. if(ch == (uint32_t)',')
  791. need_escape = 1;
  792. }
  793. }
  794. else
  795. {
  796. if(fg == 0x10)
  797. cur += sprintf(cur, "\x0f\x03,%d", bg);
  798. else
  799. cur += sprintf(cur, "\x03%d,%d", fg, bg);
  800. }
  801. if(ch >= (uint32_t)'0' && ch <= (uint32_t)'9')
  802. need_escape = 1;
  803. if(need_escape)
  804. cur += sprintf(cur, "\x02\x02");
  805. }
  806. cur += caca_utf32_to_utf8(cur, ch);
  807. prevfg = fg;
  808. prevbg = bg;
  809. }
  810. /* TODO: do the same the day we optimise whole lines above */
  811. if(!cv->width)
  812. *cur++ = ' ';
  813. *cur++ = '\r';
  814. *cur++ = '\n';
  815. }
  816. /* Crop to really used size */
  817. debug("IRC export: alloc %lu bytes, realloc %lu",
  818. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  819. *bytes = (uintptr_t)(cur - data);
  820. data = realloc(data, *bytes);
  821. return data;
  822. }
  823. /* Export a PostScript document. */
  824. static void *export_ps(caca_canvas_t const *cv, size_t *bytes)
  825. {
  826. static char const *ps_header =
  827. "%!\n"
  828. "%% libcaca PDF export\n"
  829. "%%LanguageLevel: 2\n"
  830. "%%Pages: 1\n"
  831. "%%DocumentData: Clean7Bit\n"
  832. "/csquare {\n"
  833. " newpath\n"
  834. " 0 0 moveto\n"
  835. " 0 1 rlineto\n"
  836. " 1 0 rlineto\n"
  837. " 0 -1 rlineto\n"
  838. " closepath\n"
  839. " setrgbcolor\n"
  840. " fill\n"
  841. "} def\n"
  842. "/S {\n"
  843. " Show\n"
  844. "} bind def\n"
  845. "/Courier-Bold findfont\n"
  846. "8 scalefont\n"
  847. "setfont\n"
  848. "gsave\n"
  849. "6 10 scale\n";
  850. char *data, *cur;
  851. int x, y;
  852. /* 200 is arbitrary but should be ok */
  853. *bytes = strlen(ps_header) + 100 + cv->height * (32 + cv->width * 200);
  854. cur = data = malloc(*bytes);
  855. /* Header */
  856. cur += sprintf(cur, "%s", ps_header);
  857. cur += sprintf(cur, "0 %d translate\n", cv->height);
  858. /* Background, drawn using csquare macro defined in header */
  859. for(y = cv->height; y--; )
  860. {
  861. uint32_t *lineattr = cv->attrs + y * cv->width;
  862. for(x = 0; x < cv->width; x++)
  863. {
  864. uint8_t argb[8];
  865. caca_attr_to_argb64(*lineattr++, argb);
  866. cur += sprintf(cur, "1 0 translate\n %f %f %f csquare\n",
  867. (float)argb[1] * (1.0 / 0xf),
  868. (float)argb[2] * (1.0 / 0xf),
  869. (float)argb[3] * (1.0 / 0xf));
  870. }
  871. /* Return to beginning of the line, and jump to the next one */
  872. cur += sprintf(cur, "-%d 1 translate\n", cv->width);
  873. }
  874. cur += sprintf(cur, "grestore\n"); /* Restore transformation matrix */
  875. cur += sprintf(cur, "0 %d translate\n", cv->height*10);
  876. for(y = cv->height; y--; )
  877. {
  878. uint32_t *lineattr = cv->attrs + (cv->height - y - 1) * cv->width;
  879. uint32_t *linechar = cv->chars + (cv->height - y - 1) * cv->width;
  880. for(x = 0; x < cv->width; x++)
  881. {
  882. uint8_t argb[8];
  883. uint32_t ch = *linechar++;
  884. caca_attr_to_argb64(*lineattr++, argb);
  885. cur += sprintf(cur, "newpath\n");
  886. cur += sprintf(cur, "%d %d moveto\n", (x + 1) * 6, y * 10 + 2);
  887. cur += sprintf(cur, "%f %f %f setrgbcolor\n",
  888. (float)argb[5] * (1.0 / 0xf),
  889. (float)argb[6] * (1.0 / 0xf),
  890. (float)argb[7] * (1.0 / 0xf));
  891. if(ch < 0x00000020)
  892. cur += sprintf(cur, "(?) show\n");
  893. else if(ch >= 0x00000080)
  894. cur += sprintf(cur, "(?) show\n");
  895. else switch((uint8_t)(ch & 0x7f))
  896. {
  897. case '\\':
  898. case '(':
  899. case ')':
  900. cur += sprintf(cur, "(\\%c) show\n", (uint8_t)ch);
  901. break;
  902. default:
  903. cur += sprintf(cur, "(%c) show\n", (uint8_t)ch);
  904. break;
  905. }
  906. }
  907. }
  908. cur += sprintf(cur, "showpage\n");
  909. /* Crop to really used size */
  910. debug("PS export: alloc %lu bytes, realloc %lu",
  911. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  912. *bytes = (uintptr_t)(cur - data);
  913. data = realloc(data, *bytes);
  914. return data;
  915. }
  916. /* Export an SVG vector image */
  917. static void *export_svg(caca_canvas_t const *cv, size_t *bytes)
  918. {
  919. static char const svg_header[] =
  920. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  921. "<svg width=\"%d\" height=\"%d\" viewBox=\"0 0 %d %d\""
  922. " xmlns=\"http://www.w3.org/2000/svg\""
  923. " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
  924. " xml:space=\"preserve\" version=\"1.1\" baseProfile=\"full\">\n";
  925. char *data, *cur;
  926. int x, y;
  927. /* 200 is arbitrary but should be ok */
  928. *bytes = strlen(svg_header) + 128 + cv->width * cv->height * 200;
  929. cur = data = malloc(*bytes);
  930. /* Header */
  931. cur += sprintf(cur, svg_header, cv->width * 6, cv->height * 10,
  932. cv->width * 6, cv->height * 10);
  933. cur += sprintf(cur, " <g id=\"mainlayer\" font-size=\"10\""
  934. " style=\"font-family: monospace\">\n");
  935. /* Background */
  936. for(y = 0; y < cv->height; y++)
  937. {
  938. uint32_t *lineattr = cv->attrs + y * cv->width;
  939. for(x = 0; x < cv->width; x++)
  940. {
  941. cur += sprintf(cur, "<rect style=\"fill:#%.03x\" x=\"%d\" y=\"%d\""
  942. " width=\"6\" height=\"10\"/>\n",
  943. caca_attr_to_rgb12_bg(*lineattr++),
  944. x * 6, y * 10);
  945. }
  946. }
  947. /* Text */
  948. for(y = 0; y < cv->height; y++)
  949. {
  950. uint32_t *lineattr = cv->attrs + y * cv->width;
  951. uint32_t *linechar = cv->chars + y * cv->width;
  952. for(x = 0; x < cv->width; x++)
  953. {
  954. uint32_t ch = *linechar++;
  955. if(ch == ' ' || ch == CACA_MAGIC_FULLWIDTH)
  956. {
  957. lineattr++;
  958. continue;
  959. }
  960. cur += sprintf(cur, "<text style=\"fill:#%.03x\" "
  961. "x=\"%d\" y=\"%d\">",
  962. caca_attr_to_rgb12_fg(*lineattr++),
  963. x * 6, (y * 10) + 8);
  964. if(ch < 0x00000020)
  965. *cur++ = '?';
  966. else if(ch > 0x0000007f)
  967. cur += caca_utf32_to_utf8(cur, ch);
  968. else switch((uint8_t)ch)
  969. {
  970. case '>': cur += sprintf(cur, "&gt;"); break;
  971. case '<': cur += sprintf(cur, "&lt;"); break;
  972. case '&': cur += sprintf(cur, "&amp;"); break;
  973. default: *cur++ = (uint8_t)ch; break;
  974. }
  975. cur += sprintf(cur, "</text>\n");
  976. }
  977. }
  978. cur += sprintf(cur, " </g>\n");
  979. cur += sprintf(cur, "</svg>\n");
  980. /* Crop to really used size */
  981. debug("SVG export: alloc %lu bytes, realloc %lu",
  982. (unsigned long int)*bytes, (unsigned long int)(cur - data));
  983. *bytes = (uintptr_t)(cur - data);
  984. data = realloc(data, *bytes);
  985. return data;
  986. }
  987. /* Export a TGA image */
  988. static void *export_tga(caca_canvas_t const *cv, size_t *bytes)
  989. {
  990. char const * const *fontlist;
  991. char *data, *cur;
  992. caca_font_t *f;
  993. int i, w, h;
  994. fontlist = caca_get_font_list();
  995. if(!fontlist[0])
  996. {
  997. seterrno(EINVAL);
  998. return NULL;
  999. }
  1000. f = caca_load_font(fontlist[0], 0);
  1001. w = caca_get_canvas_width(cv) * caca_get_font_width(f);
  1002. h = caca_get_canvas_height(cv) * caca_get_font_height(f);
  1003. *bytes = w * h * 4 + 18; /* 32 bpp + 18 bytes for the header */
  1004. cur = data = malloc(*bytes);
  1005. /* ID Length */
  1006. cur += sprintf(cur, "%c", 0);
  1007. /* Color Map Type: no colormap */
  1008. cur += sprintf(cur, "%c", 0);
  1009. /* Image Type: uncompressed truecolor */
  1010. cur += sprintf(cur, "%c", 2);
  1011. /* Color Map Specification: no color map */
  1012. memset(cur, 0, 5); cur += 5;
  1013. /* Image Specification */
  1014. cur += sprintf(cur, "%c%c", 0, 0); /* X Origin */
  1015. cur += sprintf(cur, "%c%c", 0, 0); /* Y Origin */
  1016. cur += sprintf(cur, "%c%c", w & 0xff, w >> 8); /* Width */
  1017. cur += sprintf(cur, "%c%c", h & 0xff, h >> 8); /* Height */
  1018. cur += sprintf(cur, "%c", 32); /* Pixel Depth */
  1019. cur += sprintf(cur, "%c", 40); /* Image Descriptor */
  1020. /* Image ID: no ID */
  1021. /* Color Map Data: no colormap */
  1022. /* Image Data */
  1023. caca_render_canvas(cv, f, cur, w, h, 4 * w);
  1024. /* Swap bytes. What a waste of time. */
  1025. for(i = 0; i < w * h * 4; i += 4)
  1026. {
  1027. char c;
  1028. c = cur[i]; cur[i] = cur[i + 3]; cur[i + 3] = c;
  1029. c = cur[i + 1]; cur[i + 1] = cur[i + 2]; cur[i + 2] = c;
  1030. }
  1031. caca_free_font(f);
  1032. return data;
  1033. }
  1034. /*
  1035. * XXX: The following functions are aliases.
  1036. */
  1037. void *cucul_export_memory(cucul_canvas_t const *, char const *,
  1038. size_t *) CACA_ALIAS(caca_export_memory);
  1039. char const * const * cucul_get_export_list(void)
  1040. CACA_ALIAS(caca_get_export_list);