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