X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fdevices%2Fpdf.c;h=64c61714c9cdeaa6cb091c2d7b75edf7704c53ea;hb=10b60d36fcf6cc9532bf397866c5bdc3393246eb;hp=ba92ed0cca6b95872d8613cd3470f30dd9d15f6e;hpb=ecd7c7248b9a93163090bfe7512b2a53d8da6d95;p=swftools.git diff --git a/lib/devices/pdf.c b/lib/devices/pdf.c index ba92ed0..64c6171 100644 --- a/lib/devices/pdf.c +++ b/lib/devices/pdf.c @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include #include "../os.h" +#include "../q.h" #include "../jpeg.h" #include "../types.h" #include "../mem.h" @@ -35,6 +37,7 @@ typedef struct _internal { PDF* p; char*tempfile; + gfxfontlist_t*fontlist; } internal_t; int pdf_setparameter(gfxdevice_t*dev, const char*key, const char*value) @@ -58,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; } @@ -90,8 +156,7 @@ void pdf_startclip(gfxdevice_t*dev, gfxline_t*line) { internal_t*i = (internal_t*)dev->internal; PDF_save(i->p); - PDF_set_parameter(i->p, "fillrule", "evenodd"); - if(mkline(line, i->p)) + if(mkline(line, i->p, 1)) PDF_clip(i->p); else ; // TODO: strictly speaking, an empty clip clears everything @@ -105,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); } @@ -119,9 +186,8 @@ 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); - PDF_set_parameter(i->p, "fillrule", "evenodd"); - if(mkline(line, i->p)) { + if(mkline(line, i->p, 1)) { PDF_fill(i->p); } } @@ -151,30 +217,79 @@ void pdf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, g internal_t*i = (internal_t*)dev->internal; } +static char type3 = 1; + void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font) { internal_t*i = (internal_t*)dev->internal; + + if(type3) { + int fontid = 0; + if(!gfxfontlist_hasfont(i->fontlist, font)) { + + static int fontnr = 1; + char fontname[32]; + sprintf(fontname, "font%d", fontnr++); + int l = strlen(fontname); + char fontname2[64]; + int t; + for(t=0;tp, fontname2, l*2, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, ""); + int num = font->num_glyphs<256-32?font->num_glyphs:256-32; + for(t=0;tglyphs[t]; + gfxbbox_t bbox = gfxline_getbbox(g->line); + char name[32]; + 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, 1)) + PDF_fill(i->p); + PDF_end_glyph(i->p); + } + PDF_end_font(i->p); + fontid = PDF_load_font(i->p, fontname2, l*2, fontname, ""); + + i->fontlist = gfxfontlist_addfont2(i->fontlist, font, (void*)(ptroff_t)fontid); + } + } } void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix) { internal_t*i = (internal_t*)dev->internal; + if(!font) return; - /* align characters to whole pixels */ - matrix->tx = (int)matrix->tx; - matrix->ty = (int)matrix->ty; gfxglyph_t*glyph = &font->glyphs[glyphnr]; - gfxline_t*line2 = gfxline_clone(glyph->line); - gfxline_transform(line2, matrix); PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0); - PDF_set_parameter(i->p, "fillrule", "evenodd"); - - if(mkline(line2, i->p)) { - PDF_fill(i->p); + char as_shape = 0; + if(!type3) as_shape=1; + 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(as_shape) { + gfxline_t*line2 = gfxline_clone(glyph->line); + gfxline_transform(line2, matrix); + if(mkline(line2, i->p, 1)) { + PDF_fill(i->p); + } + gfxline_free(line2); + } else { + assert(gfxfontlist_hasfont(i->fontlist, font)); + int fontid = (int)(ptroff_t)gfxfontlist_getuserdata(i->fontlist, font->id); + 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); } - gfxline_free(line2); return; }