added gfxfilter for merging fonts
authorMatthias Kramm <kramm@quiss.org>
Sat, 6 Mar 2010 00:32:30 +0000 (16:32 -0800)
committerMatthias Kramm <kramm@quiss.org>
Sat, 6 Mar 2010 00:32:43 +0000 (16:32 -0800)
lib/Makefile.in
lib/filters/alpha.c
lib/filters/one_big_font.c [new file with mode: 0644]
lib/filters/remove_font_transforms.c
lib/gfxfilter.c
lib/gfxfilter.h
src/pdf2swf.c

index 7eef037..566cff3 100644 (file)
@@ -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)
index 5178c48..98a49af 100644 (file)
@@ -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 (file)
index 0000000..667c999
--- /dev/null
@@ -0,0 +1,117 @@
+/* remove_font_transform.c
+
+   Part of the swftools package.
+
+   Copyright (c) 2010 Matthias Kramm <kramm@quiss.org> 
+   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 <stdlib.h>
+#include <memory.h>
+#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;
+}
+
index 914428f..7e0b31c 100644 (file)
@@ -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;
index 7e182f7..24b969e 100644 (file)
@@ -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;
+    }
+}
index c34de38..6de443e 100644 (file)
 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
 }
index c7a804e..e333eb3 100644 (file)
@@ -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;
 }