From 905772d04a1c2dd73802c6dde5bd50e9701b7af6 Mon Sep 17 00:00:00 2001 From: Matthias Kramm Date: Fri, 5 Mar 2010 16:32:30 -0800 Subject: [PATCH] added gfxfilter for merging fonts --- lib/Makefile.in | 2 +- lib/filters/alpha.c | 1 + lib/filters/one_big_font.c | 117 ++++++++++++++++++++++++++++++++++ lib/filters/remove_font_transforms.c | 1 + lib/gfxfilter.c | 103 +++++++++++++++++++++++++++++- lib/gfxfilter.h | 21 +++++- src/pdf2swf.c | 30 +++++++++ 7 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 lib/filters/one_big_font.c diff --git a/lib/Makefile.in b/lib/Makefile.in index 7eef037..566cff3 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -20,7 +20,7 @@ rfxswf_modules = modules/swfbits.c modules/swfaction.c modules/swfdump.c module base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O) ttf.$(O) devices=devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@ -filters=filters/alpha.$(O) filters/remove_font_transforms.$(O) +filters=filters/alpha.$(O) filters/remove_font_transforms.$(O) filters/one_big_font.$(O) gfx_objects=gfximage.$(O) gfxtools.$(O) gfxfont.$(O) gfxfilter.$(O) $(devices) $(filters) rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O) diff --git a/lib/filters/alpha.c b/lib/filters/alpha.c index 5178c48..98a49af 100644 --- a/lib/filters/alpha.c +++ b/lib/filters/alpha.c @@ -105,6 +105,7 @@ void gfxfilter_maketransparent_init(gfxfilter_t*f, U8 alpha) i->alpha = alpha; memset(f, 0, sizeof(gfxfilter_t)); + f->type = gfxfilter_onepass; f->name = "maketransparent"; f->internal = i; f->stroke = maketransparent_stroke; diff --git a/lib/filters/one_big_font.c b/lib/filters/one_big_font.c new file mode 100644 index 0000000..667c999 --- /dev/null +++ b/lib/filters/one_big_font.c @@ -0,0 +1,117 @@ +/* remove_font_transform.c + + Part of the swftools package. + + Copyright (c) 2010 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include "../gfxfilter.h" +#include "../gfxtools.h" +#include "../gfxfont.h" +#include "../types.h" +#include "../mem.h" + +typedef struct _internal { + gfxfontlist_t*fonts; + gfxfont_t*font; + int num_glyphs; +} internal_t; + +typedef struct _fontdata { + gfxfont_t*font; + int start; +} fontdata_t; + +static void pass1_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out) +{ + internal_t*i = (internal_t*)f->internal; + fontdata_t*d = gfxfontlist_getuserdata(i->fonts, font->id); + if(!d) { + d = rfx_calloc(sizeof(fontdata_t)); + d->font = font; + d->start = i->num_glyphs; + i->num_glyphs += font->num_glyphs; + i->fonts = gfxfontlist_addfont2(i->fonts, font, d); + } + out->drawchar(out, font, glyphnr, color, matrix); +} +static gfxresult_t*pass1_finish(gfxfilter_t*f, gfxdevice_t*out) +{ + internal_t*i = (internal_t*)f->internal; + gfxfont_t*font = i->font = rfx_calloc(sizeof(gfxfont_t)); + font->id = strdup("onebigfont"); + font->num_glyphs = i->num_glyphs; + font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*i->num_glyphs); + gfxfontlist_t*l = i->fonts; + while(l) { + gfxfont_t*old = l->font; + fontdata_t*d = l->user; + memcpy(font->glyphs + d->start, old->glyphs, sizeof(gfxglyph_t)*old->num_glyphs); + if(old->ascent > font->ascent) + font->ascent = old->ascent; + if(old->descent > font->descent) + font->descent = old->descent; + l = l->next; + } + gfxfont_fix_unicode(font); + return out->finish(out); +} + +static void pass2_addfont(gfxfilter_t*f, gfxfont_t*font, gfxdevice_t*out) +{ + internal_t*i = (internal_t*)f->internal; + out->addfont(out, i->font); +} +static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out) +{ + internal_t*i = (internal_t*)f->internal; + fontdata_t*d = gfxfontlist_getuserdata(i->fonts, font->id); + out->drawchar(out, i->font, glyphnr + d->start, color, matrix); +} +static gfxresult_t*pass2_finish(gfxfilter_t*f, gfxdevice_t*out) +{ + internal_t*i = (internal_t*)f->internal; + // clean up + gfxfontlist_t*l = i->fonts; + while(l) { + free(l->user);l->user=0; + l=l->next; + } + gfxfontlist_free(i->fonts, 0);i->fonts=0; + return out->finish(out); +} + +void gfxtwopassfilter_one_big_font_init(gfxtwopassfilter_t*f) +{ + internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); + + memset(f, 0, sizeof(gfxtwopassfilter_t)); + f->type = gfxfilter_twopass; + + f->pass1.name = "filter \"one big font\" pass 1"; + f->pass1.drawchar = pass1_drawchar; + f->pass1.finish = pass1_finish; + f->pass1.internal = i; + + f->pass2.name = "filter \"one big font\" pass 2"; + f->pass2.addfont = pass2_addfont; + f->pass2.drawchar = pass2_drawchar; + f->pass2.finish = pass2_finish; + f->pass2.internal = i; +} + diff --git a/lib/filters/remove_font_transforms.c b/lib/filters/remove_font_transforms.c index 914428f..7e0b31c 100644 --- a/lib/filters/remove_font_transforms.c +++ b/lib/filters/remove_font_transforms.c @@ -44,6 +44,7 @@ void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f) { internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); memset(f, 0, sizeof(gfxtwopassfilter_t)); + f->type = gfxfilter_twopass; f->pass1.name = "remove font transforms pass 1"; f->pass1.drawchar = pass1_drawchar; f->pass1.internal = i; diff --git a/lib/gfxfilter.c b/lib/gfxfilter.c index 7e182f7..24b969e 100644 --- a/lib/gfxfilter.c +++ b/lib/gfxfilter.c @@ -25,6 +25,7 @@ #include "mem.h" #include "gfxfilter.h" #include "devices/record.h" +#include "q.h" typedef struct _internal { gfxfilter_t*filter; @@ -304,7 +305,7 @@ static gfxresult_t* twopass_finish(gfxdevice_t*dev) } i->pass++; - gfxresult_record_replay(r, i->out); + gfxresult_record_replay(r, dev); r->destroy(r); return twopass_finish(dev); @@ -335,3 +336,103 @@ gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*_twopass, gfxdevice_t*out) return dev; } +gfxfilterchain_t* gfxfilterchain_parse(const char*_filterexpr) +{ + char*filterexpr = strdup(_filterexpr); + char*f = filterexpr; + char*end = filterexpr+strlen(filterexpr); + dict_t* params = dict_new2(&charptr_type); + char*cmd = 0; + + gfxfilterchain_t*chain = 0; + gfxfilterchain_t*next = 0; + + if(!*f) + return 0; + + while(1) { + char* eq = strchr(f, '='); + char* colon = strchr(f, ':'); + char lastitem = 0; + if(!colon) { + colon = end; + lastitem = 1; + } + *colon = 0; + char*newcmd = 0; + char param = 0; + + /* fixme: change this from a dict_t to gfxparams_t? */ + if(eq && eq < colon) { // parameter + *eq = 0; + if(!cmd) { + fprintf(stderr, "Error: need a filter before specifying parameters (%s=%s)\n", f, eq+1); + return 0; + } + dict_put(params, f, strdup(eq+1)); + param = 1; + } else { + newcmd = f; + } + if(!param || lastitem) { + if(!cmd && lastitem) + cmd = newcmd; + gfxfilterbase_t*f = 0; + if(!strcmp(cmd, "maketransparent")) { + char*alphastr = dict_lookup(params, "alpha"); + int alpha = 255; + if(alphastr) alpha=atoi(alphastr); + f = malloc(sizeof(gfxfilter_t)); + gfxfilter_maketransparent_init((gfxfilter_t*)f, alpha); + } else if(!strcmp(cmd, "remove_font_transforms")) { + f = malloc(sizeof(gfxtwopassfilter_t)); + gfxtwopassfilter_remove_font_transforms_init((gfxtwopassfilter_t*)f); + } else if(!strcmp(cmd, "one_big_font")) { + f = malloc(sizeof(gfxtwopassfilter_t)); + gfxtwopassfilter_one_big_font_init((gfxtwopassfilter_t*)f); + } else { + fprintf(stderr, "Unknown filter: %s\n", cmd); + return 0; + } + dict_clear(params); + gfxfilterchain_t*n = rfx_calloc(sizeof(gfxfilterchain_t)); + if(!chain) { + chain = next = n; + } else { + next->next = n; + next = n; + } + n->filter = f; + + cmd = newcmd; + if(lastitem) break; + } + f = colon+1; + } + dict_destroy(params); + return chain; +} + +gfxdevice_t* gfxfilterchain_apply(gfxfilterchain_t*chain, gfxdevice_t*dev) +{ + while(chain) { + if(chain->filter->type == gfxfilter_onepass) { + dev = gfxfilter_apply((gfxfilter_t*)chain->filter, dev); + } else if(chain->filter->type == gfxfilter_twopass) { + dev = gfxtwopassfilter_apply((gfxtwopassfilter_t*)chain->filter, dev); + } else { + fprintf(stderr, "Internal error in gfxfilterchain_apply- unknown filter type %d\n", chain->filter->type); + } + chain = chain->next; + } + return dev; +} + +void gfxfilterchain_destroy(gfxfilterchain_t*chain) +{ + while(chain) { + gfxfilterchain_t*next = chain->next; + free(chain); + chain = next; + } +} diff --git a/lib/gfxfilter.h b/lib/gfxfilter.h index c34de38..6de443e 100644 --- a/lib/gfxfilter.h +++ b/lib/gfxfilter.h @@ -28,10 +28,19 @@ extern "C" { #endif +typedef enum {gfxfilter_none, gfxfilter_onepass, gfxfilter_twopass} gfxfiltertype_t; + +typedef struct _gfxfilterbase +{ + gfxfiltertype_t type; +} gfxfilterbase_t; + typedef struct _gfxfilter { + gfxfiltertype_t type; int num_passes; const char*name; + int pass; int (*setparameter)(struct _gfxfilter*in, const char*key, const char*value, struct _gfxdevice*out); @@ -55,6 +64,7 @@ typedef struct _gfxfilter typedef struct _gfxtwopassfilter { + gfxfiltertype_t type; gfxfilter_t pass1; gfxfilter_t pass2; } gfxtwopassfilter_t; @@ -62,6 +72,15 @@ typedef struct _gfxtwopassfilter gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*dev); gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*filter, gfxdevice_t*dev); +typedef struct _gfxfilterchain { + gfxfilterbase_t*filter; + struct _gfxfilterchain*next; +} gfxfilterchain_t; + +gfxfilterchain_t* gfxfilterchain_parse(const char*filterexpr); +gfxdevice_t* gfxfilterchain_apply(gfxfilterchain_t*chain, gfxdevice_t*dev); +void gfxfilterchain_destroy(gfxfilterchain_t*chain); + #define wrap_filter(dev, name, args...) \ {gfxfilter_t f_##name; \ gfxfilter_##name##_init(&f_##name, ## args); \ @@ -77,8 +96,8 @@ gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*filter, gfxdevice_t*dev); /* known filters */ void gfxfilter_maketransparent_init(gfxfilter_t*f, U8 alpha); void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f); +void gfxtwopassfilter_one_big_font_init(gfxtwopassfilter_t*f); -void check_filter(); #ifdef __cplusplus } diff --git a/src/pdf2swf.c b/src/pdf2swf.c index c7a804e..e333eb3 100644 --- a/src/pdf2swf.c +++ b/src/pdf2swf.c @@ -72,6 +72,8 @@ static int max_time = 0; static int flatten = 0; +static char* filters = 0; + char* fontpaths[256]; int fontpathpos = 0; @@ -335,6 +337,20 @@ int args_callback_option(char*name,char*val) { store_parameter("extrafontdata", "1"); return 0; } + else if (!strcmp(name, "ff")) + { + if(filters) { + // append this to the current filter expression (we allow more than one --filter) + int l = strlen(filters); + int new_len = l + strlen(val) + 2; + filters = (char*)realloc(filters, new_len); + filters[l] = ':'; + strcpy(filters+l+1, val); + } else { + filters = strdup(val); + } + return 1; + } else if (!strcmp(name, "w")) { store_parameter("linksopennewwindow", "0"); @@ -455,6 +471,7 @@ static struct options_t options[] = { {"t", "stop"}, {"T", "flashversion"}, {"F", "fontdir"}, +{"ff", "filter"}, {"b", "defaultviewer"}, {"l", "defaultloader"}, {"B", "viewer"}, @@ -589,6 +606,16 @@ gfxdevice_t*create_output_device() out = &rescale; } + if(filters) { + gfxfilterchain_t*chain = gfxfilterchain_parse(filters); + if(!chain) { + fprintf(stderr, "Unable to parse filters: %s\n", filters); + exit(1); + } + out = gfxfilterchain_apply(chain, out); + gfxfilterchain_destroy(chain); + } + /* pass global parameters to output device */ parameter_t*p = device_config; while(p) { @@ -888,6 +915,9 @@ int main(int argn, char *argv[]) p->next = 0;free(p); p = next; } + if(filters) { + free(filters); + } return 0; } -- 1.7.10.4