* Got rid of static buffers; we now use cucul_free() to free exported buffers. * Fixed light background in the ANSI exporter by adding escape sequences for most terminal emulators.tags/v0.99.beta14
@@ -85,8 +85,7 @@ struct driver_private | |||
char prefix[sizeof(INIT_PREFIX)]; | |||
char *buffer; | |||
int size; | |||
struct cucul_buffer *ex; | |||
int client_count; | |||
struct client *clients; | |||
@@ -169,8 +168,7 @@ static int network_init_graphics(caca_t *kk) | |||
return -1; | |||
} | |||
kk->drv.p->buffer = NULL; | |||
kk->drv.p->size = 0; | |||
kk->drv.p->ex = NULL; | |||
/* Ignore SIGPIPE */ | |||
kk->drv.p->sigpipe_handler = signal(SIGPIPE, SIG_IGN); | |||
@@ -191,6 +189,9 @@ static int network_end_graphics(caca_t *kk) | |||
kk->drv.p->clients[i].fd = -1; | |||
} | |||
if(kk->drv.p->ex) | |||
cucul_free(kk->drv.p->ex); | |||
/* Restore SIGPIPE handler */ | |||
signal(SIGPIPE, kk->drv.p->sigpipe_handler); | |||
@@ -219,10 +220,17 @@ static void network_display(caca_t *kk) | |||
{ | |||
int i; | |||
/* Free the previous export buffer, if any */ | |||
if(kk->drv.p->ex) | |||
{ | |||
cucul_free(kk->drv.p->ex); | |||
kk->drv.p->ex = NULL; | |||
} | |||
/* Get ANSI representation of the image and skip the end-of buffer | |||
* linefeed ("\r\n\0", 3 bytes) */ | |||
kk->drv.p->buffer = cucul_get_ansi(kk->qq, 0, &kk->drv.p->size); | |||
kk->drv.p->size -= 3; | |||
kk->drv.p->ex = cucul_export(kk->qq, CUCUL_FORMAT_ANSI); | |||
kk->drv.p->ex->size -= 3; | |||
for(i = 0; i < kk->drv.p->client_count; i++) | |||
{ | |||
@@ -370,7 +378,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
} | |||
/* No error, there's just nothing to send yet */ | |||
if(!kk->drv.p->buffer) | |||
if(!kk->drv.p->ex) | |||
return 0; | |||
/* If we have backlog, send the backlog */ | |||
@@ -395,7 +403,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
{ | |||
c->start += ret; | |||
if(c->stop - c->start + strlen(ANSI_PREFIX) + kk->drv.p->size | |||
if(c->stop - c->start + strlen(ANSI_PREFIX) + kk->drv.p->ex->size | |||
> OUTBUFFER) | |||
{ | |||
/* Overflow! Empty buffer and start again */ | |||
@@ -406,7 +414,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
} | |||
/* Need to move? */ | |||
if(c->stop + strlen(ANSI_PREFIX) + kk->drv.p->size > OUTBUFFER) | |||
if(c->stop + strlen(ANSI_PREFIX) + kk->drv.p->ex->size > OUTBUFFER) | |||
{ | |||
memmove(c->outbuf, c->outbuf + c->start, c->stop - c->start); | |||
c->stop -= c->start; | |||
@@ -415,8 +423,8 @@ static int send_data(caca_t *kk, struct client *c) | |||
memcpy(c->outbuf + c->stop, ANSI_PREFIX, strlen(ANSI_PREFIX)); | |||
c->stop += strlen(ANSI_PREFIX); | |||
memcpy(c->outbuf + c->stop, kk->drv.p->buffer, kk->drv.p->size); | |||
c->stop += kk->drv.p->size; | |||
memcpy(c->outbuf + c->stop, kk->drv.p->ex->buffer, kk->drv.p->ex->size); | |||
c->stop += kk->drv.p->ex->size; | |||
return 0; | |||
} | |||
@@ -436,7 +444,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
if(ret < (ssize_t)strlen(ANSI_PREFIX)) | |||
{ | |||
if(strlen(ANSI_PREFIX) + kk->drv.p->size > OUTBUFFER) | |||
if(strlen(ANSI_PREFIX) + kk->drv.p->ex->size > OUTBUFFER) | |||
{ | |||
/* Overflow! Empty buffer and start again */ | |||
memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET)); | |||
@@ -447,14 +455,14 @@ static int send_data(caca_t *kk, struct client *c) | |||
memcpy(c->outbuf, ANSI_PREFIX, strlen(ANSI_PREFIX) - ret); | |||
c->stop = strlen(ANSI_PREFIX) - ret; | |||
memcpy(c->outbuf + c->stop, kk->drv.p->buffer, kk->drv.p->size); | |||
c->stop += kk->drv.p->size; | |||
memcpy(c->outbuf + c->stop, kk->drv.p->ex->buffer, kk->drv.p->ex->size); | |||
c->stop += kk->drv.p->ex->size; | |||
return 0; | |||
} | |||
/* Send actual data */ | |||
ret = nonblock_write(c->fd, kk->drv.p->buffer, kk->drv.p->size); | |||
ret = nonblock_write(c->fd, kk->drv.p->ex->buffer, kk->drv.p->ex->size); | |||
if(ret == -1) | |||
{ | |||
if(errno == EAGAIN) | |||
@@ -463,9 +471,9 @@ static int send_data(caca_t *kk, struct client *c) | |||
return -1; | |||
} | |||
if(ret < kk->drv.p->size) | |||
if(ret < (int)kk->drv.p->ex->size) | |||
{ | |||
if(kk->drv.p->size > OUTBUFFER) | |||
if(kk->drv.p->ex->size > OUTBUFFER) | |||
{ | |||
/* Overflow! Empty buffer and start again */ | |||
memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET)); | |||
@@ -474,8 +482,8 @@ static int send_data(caca_t *kk, struct client *c) | |||
return 0; | |||
} | |||
memcpy(c->outbuf, kk->drv.p->buffer, kk->drv.p->size - ret); | |||
c->stop = kk->drv.p->size - ret; | |||
memcpy(c->outbuf, kk->drv.p->ex->buffer, kk->drv.p->ex->size - ret); | |||
c->stop = kk->drv.p->ex->size - ret; | |||
return 0; | |||
} | |||
@@ -74,11 +74,6 @@ cucul_t * cucul_init(void) | |||
return NULL; | |||
} | |||
qq->ansi_buffer = NULL; | |||
qq->irc_buffer = NULL; | |||
qq->html3_buffer = NULL; | |||
qq->html_buffer = NULL; | |||
return qq; | |||
} | |||
@@ -277,19 +272,44 @@ void cucul_end(cucul_t *qq) | |||
free(qq->chars); | |||
free(qq->attr); | |||
if(qq->ansi_buffer) | |||
free(qq->ansi_buffer); | |||
if(qq->irc_buffer) | |||
free(qq->irc_buffer); | |||
if(qq->html3_buffer) | |||
free(qq->html3_buffer); | |||
if(qq->html_buffer) | |||
free(qq->html_buffer); | |||
if(qq->ps_buffer) | |||
free(qq->ps_buffer); | |||
free(qq); | |||
} | |||
struct cucul_buffer * cucul_export(cucul_t *qq, enum cucul_format format) | |||
{ | |||
struct cucul_buffer *ex; | |||
free(qq); | |||
ex = malloc(sizeof(struct cucul_buffer)); | |||
switch(format) | |||
{ | |||
case CUCUL_FORMAT_ANSI: | |||
_cucul_get_ansi(qq, ex); | |||
break; | |||
case CUCUL_FORMAT_HTML: | |||
_cucul_get_html(qq, ex); | |||
break; | |||
case CUCUL_FORMAT_HTML3: | |||
_cucul_get_html3(qq, ex); | |||
break; | |||
case CUCUL_FORMAT_IRC: | |||
_cucul_get_irc(qq, ex); | |||
break; | |||
case CUCUL_FORMAT_PS: | |||
_cucul_get_ps(qq, ex); | |||
break; | |||
default: | |||
free(ex); | |||
return NULL; | |||
} | |||
return ex; | |||
} | |||
void cucul_free(struct cucul_buffer *ex) | |||
{ | |||
free(ex->buffer); | |||
free(ex); | |||
} | |||
/* | |||
@@ -28,7 +28,7 @@ extern "C" | |||
/** \brief Colour definitions. | |||
* | |||
* Colours that can be used with caca_set_color(). | |||
* Colours that can be used with cucul_set_color(). | |||
*/ | |||
enum cucul_color | |||
{ | |||
@@ -50,6 +50,19 @@ enum cucul_color | |||
CUCUL_COLOR_WHITE = 15 /**< The colour index for white. */ | |||
}; | |||
/** \brief Export formats | |||
* | |||
* Export formats understood by libcucul. | |||
*/ | |||
enum cucul_format | |||
{ | |||
CUCUL_FORMAT_ANSI = 0, /**< Export to ANSI format. */ | |||
CUCUL_FORMAT_HTML = 1, /**< Export to HTML format. */ | |||
CUCUL_FORMAT_HTML3 = 2, /**< Export to old HTMLv3 format. */ | |||
CUCUL_FORMAT_IRC = 3, /**< Export to text with mIRC colours. */ | |||
CUCUL_FORMAT_PS = 4, /**< Export to PostScript. */ | |||
}; | |||
/** \brief Internal features. | |||
* | |||
* Internal libcaca features such as the rendering method or the dithering | |||
@@ -200,15 +213,18 @@ void cucul_free_bitmap(cucul_t *, struct cucul_bitmap *); | |||
/** \defgroup exporter Exporters to various formats | |||
* | |||
* These functions exports current image to various text formats | |||
* Returned buffer will be freed() each you'll call the exporter function. | |||
* These functions export the current canvas to various text formats. It | |||
* is necessary to call cucul_free() to dispose of the data. | |||
* | |||
* @{ */ | |||
char* cucul_get_html(cucul_t *, int *size); | |||
char* cucul_get_html3(cucul_t *, int *size); | |||
char* cucul_get_irc(cucul_t *, int *size); | |||
char* cucul_get_ansi(cucul_t *, int trailing, int *size); | |||
char* cucul_get_ps(cucul_t *qq, int *size); | |||
struct cucul_buffer | |||
{ | |||
unsigned int size; | |||
char *buffer; | |||
}; | |||
struct cucul_buffer * cucul_export(cucul_t *, enum cucul_format); | |||
void cucul_free(struct cucul_buffer *); | |||
/* @} */ | |||
@@ -47,13 +47,6 @@ struct cucul_context | |||
enum cucul_feature background, antialiasing, dithering; | |||
unsigned int refcount; | |||
/* Exporters facilities */ | |||
char *ansi_buffer; | |||
char *irc_buffer; | |||
char *html3_buffer; | |||
char *html_buffer; | |||
char *ps_buffer; | |||
}; | |||
/* Initialisation functions */ | |||
@@ -10,7 +10,7 @@ | |||
*/ | |||
/** \file export.c | |||
* \version \$Id: export.c 361 2006-03-09 13:24:06Z jylam $ | |||
* \version \$Id$ | |||
* \author Sam Hocevar <sam@zoy.org> | |||
* \author Jean-Yves Lamoureux <jylam@lnxscene.org> | |||
* \brief Export function | |||
@@ -39,28 +39,24 @@ | |||
* able to cut/paste the result to a function like printf | |||
* \return buffer containing generated ANSI codes as a big string | |||
*/ | |||
char * cucul_get_ansi(cucul_t *qq, int trailing, int *size) | |||
void _cucul_get_ansi(cucul_t *qq, struct cucul_buffer *ex) | |||
{ | |||
static int const palette[] = | |||
{ | |||
30, 34, 32, 36, 31, 35, 33, 37, /* Both lines (light and dark) are the same, */ | |||
30, 34, 32, 36, 31, 35, 33, 37, /* light colors handling is done later */ | |||
0, 4, 2, 6, 1, 5, 3, 7, | |||
8, 12, 10, 14, 9, 13, 11, 15 | |||
}; | |||
char *cur; | |||
unsigned int x, y; | |||
/* 20 bytes assumed for max length per pixel. | |||
/* 23 bytes assumed for max length per pixel ('\e[5;1;3x;4y;9x;10ym' plus | |||
* 4 max bytes for a UTF-8 character). | |||
* Add height*9 to that (zeroes color at the end and jump to next line) */ | |||
if(qq->ansi_buffer) | |||
free(qq->ansi_buffer); | |||
qq->ansi_buffer = malloc(((qq->height*9) + (qq->width * qq->height * 20)) * sizeof(char)); | |||
if(qq->ansi_buffer == NULL) | |||
return NULL; | |||
ex->size = (qq->height * 9) + (qq->width * qq->height * 23); | |||
ex->buffer = malloc(ex->size); | |||
cur = qq->ansi_buffer; | |||
// *cur++ = ''; | |||
cur = ex->buffer; | |||
for(y = 0; y < qq->height; y++) | |||
{ | |||
@@ -73,34 +69,39 @@ char * cucul_get_ansi(cucul_t *qq, int trailing, int *size) | |||
for(x = 0; x < qq->width; x++) | |||
{ | |||
uint8_t fg = palette[lineattr[x] & 0x0f]; | |||
uint8_t bg = (palette[lineattr[x] >> 4])+10; | |||
uint8_t bg = palette[lineattr[x] >> 4]; | |||
uint32_t c = linechar[x]; | |||
if(!trailing) | |||
cur += sprintf(cur, "\033["); | |||
else | |||
cur += sprintf(cur, "\\033["); | |||
if(fg != prevfg || bg != prevbg) | |||
{ | |||
cur += sprintf(cur, "\033[0;"); | |||
if(fg < 8) | |||
if(bg < 8) | |||
cur += sprintf(cur, "3%d;4%dm", fg, bg); | |||
else | |||
cur += sprintf(cur, "5;3%d;4%d;10%dm", | |||
fg, bg - 8, bg - 8); | |||
else | |||
if(bg < 8) | |||
cur += sprintf(cur, "1;3%d;4%d;9%dm", | |||
fg - 8, bg, fg - 8); | |||
else | |||
cur += sprintf(cur, "5;1;3%d;4%d;9%d;10%dm", | |||
fg - 8, bg - 8, fg - 8, bg - 8); | |||
} | |||
if(fg > 7) | |||
cur += sprintf(cur, "1;%d;%dm",fg,bg); | |||
else | |||
cur += sprintf(cur, "0;%d;%dm",fg,bg); | |||
*cur++ = c & 0x7f; | |||
if((c == '%') && trailing) | |||
*cur++ = c & 0x7f; | |||
prevfg = fg; | |||
prevbg = bg; | |||
} | |||
if(!trailing) | |||
cur += sprintf(cur, "\033[0m\r\n"); | |||
else | |||
cur += sprintf(cur, "\\033[0m\\n\n"); | |||
cur += sprintf(cur, "\033[0m\r\n"); | |||
} | |||
/* Crop to really used size */ | |||
*size = (strlen(qq->ansi_buffer) + 1)* sizeof(char); | |||
qq->ansi_buffer = realloc(qq->ansi_buffer, *size); | |||
return qq->ansi_buffer; | |||
ex->size = strlen(ex->buffer) + 1; | |||
ex->buffer = realloc(ex->buffer, ex->size); | |||
} | |||
@@ -10,7 +10,7 @@ | |||
*/ | |||
/** \file export.c | |||
* \version \$Id: export.c 361 2006-03-09 13:24:06Z jylam $ | |||
* \version \$Id$ | |||
* \author Sam Hocevar <sam@zoy.org> | |||
* \author Jean-Yves Lamoureux <jylam@lnxscene.org> | |||
* \brief Export function | |||
@@ -38,7 +38,7 @@ | |||
* This function generates and returns the HTML representation of | |||
* the current image. | |||
*/ | |||
char* cucul_get_html(cucul_t *qq, int *size) | |||
void _cucul_get_html(cucul_t *qq, struct cucul_buffer *ex) | |||
{ | |||
static int const palette[] = | |||
{ | |||
@@ -51,15 +51,10 @@ char* cucul_get_html(cucul_t *qq, int *size) | |||
/* 13000 -> css palette | |||
* 40 -> max size used for a pixel (plus 10, never know)*/ | |||
/* FIXME: Check this value */ | |||
if(qq->html_buffer) | |||
free(qq->html_buffer); | |||
ex->size = 13000 + (qq->width * qq->height * 40); | |||
ex->buffer = malloc(ex->size); | |||
qq->html_buffer = malloc((13000 + ((qq->width*qq->height) * 40)) * sizeof(char)); | |||
if(qq->html_buffer == NULL) | |||
return NULL; | |||
cur = qq->html_buffer; | |||
cur = ex->buffer; | |||
/* HTML header */ | |||
cur += sprintf(cur, "<html>\n<head>\n<title>Generated by libcaca %s</title>\n", VERSION); | |||
@@ -104,10 +99,8 @@ char* cucul_get_html(cucul_t *qq, int *size) | |||
cur += sprintf(cur, "</div></body></html>\n"); | |||
/* Crop to really used size */ | |||
*size = (strlen(qq->html_buffer) + 1) * sizeof(char); | |||
qq->html_buffer = realloc(qq->html_buffer, *size); | |||
return qq->html_buffer; | |||
ex->size = strlen(ex->buffer) + 1; | |||
ex->buffer = realloc(ex->buffer, ex->size); | |||
} | |||
@@ -119,7 +112,7 @@ char* cucul_get_html(cucul_t *qq, int *size) | |||
* Won't work under gecko (mozilla rendering engine) unless you set | |||
* a correct header. | |||
*/ | |||
char* cucul_get_html3(cucul_t *qq, int *size) | |||
void _cucul_get_html3(cucul_t *qq, struct cucul_buffer *ex) | |||
{ | |||
static int const palette[] = | |||
{ | |||
@@ -128,20 +121,16 @@ char* cucul_get_html3(cucul_t *qq, int *size) | |||
0x444444, 0x4444ff, 0x44ff44, 0x44ffff, | |||
0xff4444, 0xff44ff, 0xffff44, 0xffffff, | |||
}; | |||
char *cur; | |||
unsigned int x, y, len; | |||
/* 13000 -> css palette | |||
* 40 -> max size used for a pixel (plus 10, never know) */ | |||
ex->size = 13000 + (qq->width * qq->height * 40); | |||
ex->buffer = malloc(ex->size); | |||
if(qq->html3_buffer) | |||
free(qq->html3_buffer); | |||
qq->html3_buffer = malloc((13000 + ((qq->width*qq->height)*40))*sizeof(char)); | |||
if(qq->html3_buffer == NULL) | |||
return NULL; | |||
cur = qq->html3_buffer; | |||
cur = ex->buffer; | |||
/* Table */ | |||
cur += sprintf(cur, "<table cols='%d' cellpadding='0' cellspacing='0'>\n", | |||
@@ -189,10 +178,8 @@ char* cucul_get_html3(cucul_t *qq, int *size) | |||
cur += sprintf(cur, "</table>\n"); | |||
/* Crop to really used size */ | |||
*size = (strlen(qq->html3_buffer) + 1) * sizeof(char); | |||
qq->html3_buffer = realloc(qq->html3_buffer, *size); | |||
return qq->html3_buffer; | |||
ex->size = strlen(ex->buffer) + 1; | |||
ex->buffer = realloc(ex->buffer, ex->size); | |||
} | |||
@@ -10,7 +10,7 @@ | |||
*/ | |||
/** \file export.c | |||
* \version \$Id: export.c 361 2006-03-09 13:24:06Z jylam $ | |||
* \version \$Id$ | |||
* \author Sam Hocevar <sam@zoy.org> | |||
* \author Jean-Yves Lamoureux <jylam@lnxscene.org> | |||
* \brief Export function | |||
@@ -36,7 +36,7 @@ | |||
* This function generates and returns an IRC representation of | |||
* the current image. | |||
*/ | |||
char* cucul_get_irc(cucul_t *qq, int *size) | |||
void _cucul_get_irc(cucul_t *qq, struct cucul_buffer *ex) | |||
{ | |||
static int const palette[] = | |||
{ | |||
@@ -55,14 +55,10 @@ char* cucul_get_irc(cucul_t *qq, int *size) | |||
* In real life, the average bytes per pixel value will be around 5. | |||
*/ | |||
if(qq->irc_buffer) | |||
free(qq->irc_buffer); | |||
ex->size = 2 + (qq->width * qq->height * 11); | |||
ex->buffer = malloc(ex->size); | |||
qq->irc_buffer = malloc((2 + (qq->width * qq->height * 11)) * sizeof(char)); | |||
if(qq->irc_buffer == NULL) | |||
return NULL; | |||
cur = qq->irc_buffer; | |||
cur = ex->buffer; | |||
*cur++ = '\x0f'; | |||
@@ -114,8 +110,6 @@ char* cucul_get_irc(cucul_t *qq, int *size) | |||
*cur++ = '\x0f'; | |||
/* Crop to really used size */ | |||
*size = (strlen(qq->irc_buffer) + 1) * sizeof(char); | |||
qq->irc_buffer = realloc(qq->irc_buffer, *size); | |||
return qq->irc_buffer; | |||
ex->size = strlen(ex->buffer) + 1; | |||
ex->buffer = realloc(ex->buffer, ex->size); | |||
} |
@@ -59,7 +59,7 @@ static char const *ps_header = | |||
* This function generates and returns a Postscript representation of | |||
* the current image. | |||
*/ | |||
char* cucul_get_ps(cucul_t *qq, int *size) | |||
void _cucul_get_ps(cucul_t *qq, struct cucul_buffer *ex) | |||
{ | |||
char *cur; | |||
int x, y; | |||
@@ -87,17 +87,15 @@ char* cucul_get_ps(cucul_t *qq, int *size) | |||
}; | |||
if(qq->ps_buffer) | |||
free(qq->ps_buffer); | |||
/* 200 is arbitrary but should be ok */ | |||
qq->ps_buffer = malloc((strlen(ps_header) + (qq->height*qq->width)*200) * sizeof(char)); | |||
cur = qq->ps_buffer; | |||
ex->size = strlen(ps_header) + (qq->width * qq->height * 200); | |||
ex->buffer = malloc(ex->size); | |||
cur = ex->buffer; | |||
/* Header */ | |||
cur += sprintf(cur, "%s", ps_header); | |||
/* Background, drawn using csquare macro defined in header */ | |||
for(y=(int)(qq->height-1);y>=0; y--) { | |||
uint8_t *lineattr = qq->attr + y * qq->width; | |||
@@ -139,13 +137,7 @@ char* cucul_get_ps(cucul_t *qq, int *size) | |||
cur += sprintf(cur, "showpage"); | |||
/* Crop to really used size */ | |||
*size = (strlen(qq->ps_buffer) + 1) * sizeof(char); | |||
qq->ps_buffer = realloc(qq->ps_buffer, *size); | |||
return qq->ps_buffer; | |||
ex->size = strlen(ex->buffer) + 1; | |||
ex->buffer = realloc(ex->buffer, ex->size); | |||
} | |||