libcaca  0.99.beta19
About: libcaca is a graphics library that outputs text instead of pixels, so that it can work on older video cards or text terminals (something like an advanced AAlib library).
  Fossies Dox: libcaca-0.99.beta19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

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