From: Matthias Kramm Date: Tue, 25 Aug 2009 19:36:26 +0000 (+0200) Subject: improved polygon conversion in pdf2pdf X-Git-Tag: version-0-9-1~287 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=10b60d36fcf6cc9532bf397866c5bdc3393246eb improved polygon conversion in pdf2pdf --- diff --git a/.gitignore b/.gitignore index 4b7b50e..98c707a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ swfc swfbbox font2swf src/pdf2pdf +src/gfx2gfx gif2swf pdf2swf as3compile diff --git a/lib/devices/pdf.c b/lib/devices/pdf.c index c1e1bb6..64c6171 100644 --- a/lib/devices/pdf.c +++ b/lib/devices/pdf.c @@ -27,6 +27,7 @@ #include #include #include "../os.h" +#include "../q.h" #include "../jpeg.h" #include "../types.h" #include "../mem.h" @@ -60,31 +61,94 @@ void pdf_startpage(gfxdevice_t*dev, int width, int height) PDF_set_parameter(i->p, "fillrule", "evenodd"); } -static int mkline(gfxline_t*line, PDF*p) +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) { 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; + } + + assert(!line || line->type == gfx_moveTo); + double x=0,y=0; - while(line) { - if(line->type == gfx_moveTo) { - PDF_moveto(p, line->x, line->y); - } else if(line->type == gfx_lineTo) { - PDF_lineto(p, line->x, line->y); - ret = 1; + 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); } 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 + 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; + 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; } - x = line->x; - y = line->y; - line = line->next; } + dict_destroy(start); return ret; } @@ -92,7 +156,7 @@ void pdf_startclip(gfxdevice_t*dev, gfxline_t*line) { internal_t*i = (internal_t*)dev->internal; PDF_save(i->p); - if(mkline(line, i->p)) + if(mkline(line, i->p, 1)) PDF_clip(i->p); else ; // TODO: strictly speaking, an empty clip clears everything @@ -106,13 +170,15 @@ void pdf_endclip(gfxdevice_t*dev) void pdf_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit) { internal_t*i = (internal_t*)dev->internal; + if(width<1e-6) + return; PDF_setlinewidth(i->p, width); PDF_setlinecap(i->p, cap_style==gfx_capButt?0:(cap_style==gfx_capRound?1:2)); PDF_setlinejoin(i->p, joint_style==gfx_joinMiter?0:(joint_style==gfx_joinRound?1:2)); PDF_setrgbcolor_stroke(i->p, color->r/255.0, color->g/255.0, color->b/255.0); if(joint_style==gfx_joinMiter) PDF_setmiterlimit(i->p, miterLimit); - if(mkline(line, i->p)) + if(mkline(line, i->p, 0)) PDF_stroke(i->p); } @@ -121,7 +187,7 @@ void pdf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color) internal_t*i = (internal_t*)dev->internal; PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0); - if(mkline(line, i->p)) { + if(mkline(line, i->p, 1)) { PDF_fill(i->p); } } @@ -181,7 +247,7 @@ void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font) sprintf(name, "chr%d", t+32); PDF_encoding_set_char(i->p, fontname, t+32, name, 0); PDF_begin_glyph(i->p, name, g->advance, bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax); - if(mkline(g->line, i->p)) + if(mkline(g->line, i->p, 1)) PDF_fill(i->p); PDF_end_glyph(i->p); } @@ -212,7 +278,7 @@ void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color if(as_shape) { gfxline_t*line2 = gfxline_clone(glyph->line); gfxline_transform(line2, matrix); - if(mkline(line2, i->p)) { + if(mkline(line2, i->p, 1)) { PDF_fill(i->p); } gfxline_free(line2); diff --git a/lib/q.c b/lib/q.c index 1d27b42..fc9f868 100644 --- a/lib/q.c +++ b/lib/q.c @@ -1159,6 +1159,34 @@ char dict_del(dict_t*h, const void*key) return 0; } +char dict_del2(dict_t*h, const void*key, void*data) +{ + if(!h->num) + return 0; + unsigned int hash = h->key_type->hash(key) % h->hashsize; + dictentry_t*head = h->slots[hash]; + dictentry_t*e = head, *prev=0; + while(e) { + if(h->key_type->equals(e->key, key) && e->data == data) { + dictentry_t*next = e->next; + h->key_type->free(e->key); + memset(e, 0, sizeof(dictentry_t)); + rfx_free(e); + if(e == head) { + h->slots[hash] = next; + } else { + assert(prev); + prev->next = next; + } + h->num--; + return 1; + } + prev = e; + e = e->next; + } + return 0; +} + dictentry_t* dict_get_slot(dict_t*h, const void*key) { if(!h->num) diff --git a/lib/q.h b/lib/q.h index 585d420..e255b4e 100644 --- a/lib/q.h +++ b/lib/q.h @@ -190,6 +190,7 @@ dictentry_t* dict_get_slot(dict_t*h, const void*key); char dict_contains(dict_t*h, const void*s); void* dict_lookup(dict_t*h, const void*s); char dict_del(dict_t*h, const void*s); +char dict_del2(dict_t*h, const void*key, void*data); dict_t*dict_clone(dict_t*); void dict_foreach_keyvalue(dict_t*h, void (*runFunction)(void*data, const void*key, void*val), void*data); diff --git a/lib/readers/swf.c b/lib/readers/swf.c index 132bf84..fac12e2 100644 --- a/lib/readers/swf.c +++ b/lib/readers/swf.c @@ -149,21 +149,27 @@ static gfxgradient_t* convertGradient(GRADIENT*from) gfxline_t* swfline_to_gfxline(SHAPELINE*line, int linestyle, int fillstyle0) { gfxdrawer_t d; - SCOORD x=0,y=0; + SCOORD x=0,y=0,xx=0,yy=0; gfxline_t*l; gfxdrawer_target_gfxline(&d); if(line && line->type != moveTo) { fprintf(stderr, "Warning: Shape doesn't start with a moveTo\n"); } + xx = line?line->x+1:0; while(line) { - if(line->fillstyle0 == fillstyle0 || line->fillstyle1 == fillstyle0 || + if(line->fillstyle0 == fillstyle0 || + line->fillstyle1 == fillstyle0 || line->linestyle == linestyle) { if(line->type == lineTo) { - d.moveTo(&d, x/20.0,y/20.0); + if(xx!=x || yy!=y) d.moveTo(&d, x/20.0,y/20.0); d.lineTo(&d, line->x/20.0,line->y/20.0); + xx = line->x; + yy = line->y; } else if(line->type == splineTo) { - d.moveTo(&d, x/20.0,y/20.0); + if(xx!=x || yy!=y) d.moveTo(&d, x/20.0,y/20.0); d.splineTo(&d, line->sx/20.0, line->sy/20.0, line->x/20.0,line->y/20.0); + xx = line->x; + yy = line->y; } } x = line->x; diff --git a/src/gfx2gfx.c b/src/gfx2gfx.c index 9ce3a13..85d6882 100644 --- a/src/gfx2gfx.c +++ b/src/gfx2gfx.c @@ -30,6 +30,7 @@ #include "../../swftools/lib/gfxsource.h" #include "../../swftools/lib/gfxdevice.h" #include "../../swftools/lib/gfxpoly.h" +#include "../../swftools/lib/devices/pdf.h" #include "../../swftools/lib/devices/swf.h" #include "../../swftools/lib/devices/text.h" #include "../../swftools/lib/devices/render.h" @@ -250,13 +251,19 @@ int main(int argn, char *argv[]) gfxdevice_t _out,*out=&_out; if(!strcasecmp(format, "ocr")) { gfxdevice_ocr_init(out); - } if(!strcasecmp(format, "swf")) { + } else if(!strcasecmp(format, "swf")) { gfxdevice_swf_init(out); - } if(!strcasecmp(format, "img") || !strcasecmp(format, "png")) { + } else if(!strcasecmp(format, "img") || !strcasecmp(format, "png")) { gfxdevice_render_init(out); - } if(!strcasecmp(format, "txt")) { + out->setparameter(out, "antialize", "4"); + } else if(!strcasecmp(format, "txt")) { gfxdevice_text_init(out); - } + } else if(!strcasecmp(format, "pdf")) { + gfxdevice_pdf_init(out); + } else { + msg(" Invalid output format: %s", format); + exit(1); + } int pagenr; for(pagenr = 1; pagenr <= doc->num_pages; pagenr++)