From: Matthias Kramm Date: Wed, 26 Aug 2009 15:20:20 +0000 (+0200) Subject: improved pdf output (pdf2pdf, gfx2gfx) X-Git-Tag: version-0-9-1~286 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=0b38eabf882d8bdcd0e92995e8a2478db9cb5ed8 improved pdf output (pdf2pdf, gfx2gfx) --- diff --git a/lib/devices/pdf.c b/lib/devices/pdf.c index 64c6171..ef67d49 100644 --- a/lib/devices/pdf.c +++ b/lib/devices/pdf.c @@ -37,6 +37,7 @@ typedef struct _internal { PDF* p; char*tempfile; + double lastx,lasty; gfxfontlist_t*fontlist; } internal_t; @@ -61,94 +62,40 @@ void pdf_startpage(gfxdevice_t*dev, int width, int height) PDF_set_parameter(i->p, "fillrule", "evenodd"); } -static char xy_equals(void*c1, void*c2) -{ - return !memcmp(c1, c2, sizeof(double)*2); -} -static unsigned int xy_hash(void*c) -{ - return string_hash3(c, sizeof(double)*2); -} -static void* xy_clone(void*c) -{ - void*n = malloc(sizeof(double)*2); - memcpy(n, c, sizeof(double)*2); - return n; -} -static void xy_destroy(void*c) -{ - free(c); -} -static type_t xy_type = { - hash: (hash_func)xy_hash, - equals: (equals_func)xy_equals, - dup: (dup_func)xy_clone, // all signatures are static - free: (free_func)xy_destroy, -}; - static int mkline(gfxline_t*line, PDF*p, char fill) { + double x,y; + char first = 1; int ret = 0; - - dict_t*start = dict_new2(&xy_type); - gfxline_t*l = line; - while(l) { - if(l->type == gfx_moveTo) { - double xy[2] = {l->x, l->y}; - dict_put(start, xy, l); - } - l = l->next; + char free_line = 0; + if(fill) { + line = gfxline_restitch(gfxline_clone(line)); + free_line = 1; } - - assert(!line || line->type == gfx_moveTo); - - double x=0,y=0; - double pos[2] = {0,0}; - char first = 1; - - while(dict_count(start)) { - gfxline_t*l = dict_lookup(start, pos); - if(!l) { - DICT_ITERATE_DATA(start, gfxline_t*, l2) { - l = l2; - break; - } - assert(l); - double xy[2] = {l->x,l->y}; - char d = dict_del2(start,xy,l); - assert(d); + while(line) { + if(line->type == gfx_moveTo && (x!=line->x || y!=line->y || first)) { + first = 0; + PDF_moveto(p, line->x, line->y); + } else if(line->type == gfx_lineTo) { + PDF_lineto(p, line->x, line->y); + ret = 1; } else { - char d = dict_del2(start,pos,l); - assert(d); - } - while(l) { - if(l->type == gfx_moveTo && (x!=l->x || y!=l->y || first)) { - first = 0; - PDF_moveto(p, l->x, l->y); - } else if(l->type == gfx_lineTo) { - PDF_lineto(p, l->x, l->y); - ret = 1; - } else { - /* when converting a quadratic bezier to a cubic bezier, the - two new control points are both 2/3 the way from the - endpoints to the old control point */ - double c1x = (x + l->sx*2)/3; - double c1y = (y + l->sy*2)/3; - double c2x = (l->x + l->sx*2)/3; - double c2y = (l->y + l->sy*2)/3; - PDF_curveto(p, c1x, c1y, c2x, c2y, l->x, l->y); - ret = 1; - } - x = l->x; - y = l->y; - pos[0] = x; - pos[1] = y; - l = l->next; - if(l && l->type == gfx_moveTo) - break; + /* when converting a quadratic bezier to a cubic bezier, the + two new control points are both 2/3 the way from the + endpoints to the old control point */ + double c1x = (x + line->sx*2)/3; + double c1y = (y + line->sy*2)/3; + double c2x = (line->x + line->sx*2)/3; + double c2y = (line->y + line->sy*2)/3; + PDF_curveto(p, c1x, c1y, c2x, c2y, line->x, line->y); + ret = 1; } + x = line->x; + y = line->y; + line = line->next; } - dict_destroy(start); + if(free_line) + gfxline_free(line); return ret; } @@ -273,7 +220,7 @@ void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color if(glyphnr>256-32) as_shape=1; if(fabs(matrix->m00 + matrix->m11) > 0.01) as_shape=1; if(fabs(fabs(matrix->m01) + fabs(matrix->m10)) > 0.01) as_shape=1; - if(fabs(matrix->m00) < 0.01) as_shape=1; + if(fabs(matrix->m00) < 1e-6) as_shape=1; if(as_shape) { gfxline_t*line2 = gfxline_clone(glyph->line); @@ -288,7 +235,15 @@ void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color PDF_setfont(i->p, fontid, matrix->m00); char name[32]; sprintf(name, "%c\0", glyphnr+32); - PDF_show_xy2(i->p, name, strlen(name), matrix->tx, matrix->ty); + + if(fabs(matrix->tx - i->lastx) > 0.001 || matrix->ty != i->lasty) { + PDF_show_xy2(i->p, name, strlen(name), matrix->tx, matrix->ty); + } else { + PDF_show2(i->p, name, strlen(name)); + } + + i->lastx = matrix->tx + glyph->advance*matrix->m00; + i->lasty = matrix->ty; } return; } @@ -383,6 +338,8 @@ void gfxdevice_pdf_init(gfxdevice_t*dev) dev->endpage = pdf_endpage; dev->finish = pdf_finish; + i->lastx = -1e38; + i->lasty = -1e38; i->p = PDF_new(); } diff --git a/lib/devices/swf.c b/lib/devices/swf.c index 4bf636e..764f591 100644 --- a/lib/devices/swf.c +++ b/lib/devices/swf.c @@ -2747,6 +2747,7 @@ static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) swf_Shape01DrawerInit(&draw, 0); line = font->glyphs[t].line; + while(line) { FPOINT c,to; c.x = line->sx * GLYPH_SCALE; c.y = line->sy * GLYPH_SCALE; diff --git a/lib/gfxtools.c b/lib/gfxtools.c index d8aef3f..55c4925 100644 --- a/lib/gfxtools.c +++ b/lib/gfxtools.c @@ -29,6 +29,7 @@ #include "gfxtools.h" #include "gfxfont.h" #include "jpeg.h" +#include "q.h" typedef struct _linedraw_internal { @@ -1004,6 +1005,138 @@ void gfxline_dump(gfxline_t*line, FILE*fi, char*prefix) } } +static char gfxpoint_equals(void*c1, void*c2) +{ + return !memcmp(c1, c2, sizeof(gfxpoint_t)); +} +static unsigned int gfxpoint_hash(void*c) +{ + return string_hash3(c, sizeof(gfxpoint_t)); +} +static void* gfxpoint_clone(void*c) +{ + void*n = malloc(sizeof(gfxpoint_t)); + memcpy(n, c, sizeof(gfxpoint_t)); + return n; +} +static void gfxpoint_destroy(void*c) +{ + free(c); +} +static type_t gfxpoint_type = { + hash: (hash_func)gfxpoint_hash, + equals: (equals_func)gfxpoint_equals, + dup: (dup_func)gfxpoint_clone, + free: (free_func)gfxpoint_destroy, +}; + +gfxline_t* gfxline_restitch(gfxline_t*line) +{ + dict_t*ff = dict_new2(&gfxpoint_type); + dict_t*rev = dict_new2(&gfxpoint_type); + + gfxline_t*prev=0; + while(line) { + gfxline_t*next = line->next; + if(line->type == gfx_moveTo) { + gfxpoint_t xy = {line->x, line->y}; + dict_put(ff, &xy, line); + prev = line; + } else if(!line->next || line->next->type == gfx_moveTo) { + if(prev) { + gfxpoint_t xy = {line->x, line->y}; + dict_put(rev, &xy, prev); + line->next = 0; + } + } + line = next; + } + + gfxpoint_t pos = {0,0}; + + gfxline_t*result = 0; + gfxline_t*last = 0; + + char first = 1; + while(dict_count(ff)) { + char reverse = 0, stitch = 1; + gfxline_t*l = dict_lookup(ff, &pos); + if(l) { + char d = dict_del2(ff,&pos,l);assert(d); + } else { + l = dict_lookup(rev, &pos); + if(l) { + reverse = 1; + char d = dict_del2(rev,&pos,l);assert(d); + } + } + if(!l) { + /* try to find *any* entry. this is costly, but + doesn't happen too often */ + stitch = 0; + DICT_ITERATE_DATA(ff, gfxline_t*, l2) { + l = l2; + break; + } + assert(l); + gfxpoint_t xy = {l->x,l->y}; + char d = dict_del2(ff,&xy,l);assert(d); + } + + gfxline_t*end = l; + if(!reverse) { + while(end->next) end = end->next; + pos.x = end->x; + pos.y = end->y; + char d = dict_del2(rev,&pos,l);assert(d); + } else { + l = gfxline_reverse(l); + pos.x = end->x; + pos.y = end->y; + char d = dict_del2(ff,&pos,end);assert(d); + } + + assert(l->type == gfx_moveTo); + if(stitch && !first) { + /* cut away the moveTo */ + gfxline_t*next = l->next; + free(l); + l = next; + } + + if(!last) { + result = l; + last = end; + } else { + last->next = l; + last = end; + } + first = 0; + } + dict_destroy(ff); + dict_destroy(rev); + return result; +} + +gfxline_t* gfxline_reverse(gfxline_t*line) +{ + gfxline_t*b = 0; + while(line) { + gfxline_t*next = line->next; + if(next && next->type != gfx_moveTo) { + line->type = next->type; + line->sx = next->sx; + line->sy = next->sy; + } else { + line->type = gfx_moveTo; + } + line->next = b; + b = line; + line = next; + } + return b; +} + void gfximage_save_jpeg(gfximage_t*img, char*filename, int quality) { unsigned char*data = malloc(img->width*img->height*3); diff --git a/lib/gfxtools.h b/lib/gfxtools.h index ff282a3..d038e06 100644 --- a/lib/gfxtools.h +++ b/lib/gfxtools.h @@ -74,6 +74,11 @@ void gfxbbox_intersect(gfxbbox_t*box1, gfxbbox_t*box2); void gfxline_transform(gfxline_t*line, gfxmatrix_t*matrix); +/* tries to remove unnecessary moveTos from the gfxline */ +gfxline_t* gfxline_restitch(gfxline_t*line); +/* reverses in place */ +gfxline_t* gfxline_reverse(gfxline_t*line); + void gfxmatrix_dump(gfxmatrix_t*l, FILE*fi, char*prefix); void gfxmatrix_transform(gfxmatrix_t*m, gfxcoord_t* v1, gfxcoord_t*dest); void gfxmatrix_invert(gfxmatrix_t*src, gfxmatrix_t*dest);