X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fgfxfilter.c;h=f1a341ae541fcef91e7418b837bcbf54f62c8f9a;hp=57d618019ad31c9b67dbb9972338aa25b4ad6648;hb=3116692a2512f2bfae346a1074d1fdfa00ea9d2c;hpb=944d0b42a196bd412c12c6c06fd0e4f301d4a1c7 diff --git a/lib/gfxfilter.c b/lib/gfxfilter.c index 57d6180..f1a341a 100644 --- a/lib/gfxfilter.c +++ b/lib/gfxfilter.c @@ -1,16 +1,38 @@ +/* gfxfilter.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 #include #include "mem.h" #include "gfxfilter.h" #include "devices/record.h" +#include "q.h" typedef struct _internal { gfxfilter_t*filter; gfxdevice_t*out; - gfxdevice_t*final_out; /* for two pass filters: */ + gfxdevice_t*final_out; int pass; int num_passes; gfxdevice_t record; @@ -80,7 +102,17 @@ static void filter_endpage(gfxdevice_t*dev) static gfxresult_t* filter_finish(gfxdevice_t*dev) { internal_t*i = (internal_t*)dev->internal; - gfxresult_t*r = i->filter->finish(i->filter, i->out); + gfxresult_t*r; + if(i->filter->finish) { + r = i->filter->finish(i->filter, i->out); + } else { + r = i->out->finish(i->out); + } + if(i->filter->internal) { + free(i->filter->internal); + i->filter->internal = 0; + } + free(i->filter);i->filter=0; free(dev->internal);dev->internal=0;free(dev); return r; } @@ -146,13 +178,6 @@ static void passthrough_endpage(gfxdevice_t*dev) internal_t*i = (internal_t*)dev->internal; i->out->endpage(i->out); } -gfxresult_t* passthrough_finish(gfxdevice_t*dev) -{ - internal_t*i = (internal_t*)dev->internal; - gfxdevice_t*out = i->out; - free(dev->internal);dev->internal=0;free(dev); - return out->finish(out); -} int discard_setparameter(gfxdevice_t*dev, const char*key, const char*value) { @@ -196,10 +221,12 @@ static gfxresult_t* discard_finish(gfxdevice_t*dev) return 0; } -gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*out) +gfxdevice_t*gfxfilter_apply(gfxfilter_t*_filter, gfxdevice_t*out) { internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t)); + gfxfilter_t*filter = (gfxfilter_t*)rfx_alloc(sizeof(gfxfilter_t)); + memcpy(filter, _filter, sizeof(gfxfilter_t)); i->out = out; i->filter = filter; @@ -219,18 +246,31 @@ gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*out) dev->drawchar = filter->drawchar?filter_drawchar:passthrough_drawchar; dev->drawlink = filter->drawlink?filter_drawlink:passthrough_drawlink; dev->endpage = filter->endpage?filter_endpage:passthrough_endpage; - dev->finish = filter->finish?filter_finish:passthrough_finish; + dev->finish = filter_finish; return dev; } -static void setup_twopass(gfxdevice_t*, gfxfilter_t*filter, char passthrough); +static void setup_twopass(gfxdevice_t*dev, gfxfilter_t*filter) +{ + dev->name = filter->name?filter->name:"filter"; + dev->setparameter = filter->setparameter?filter_setparameter:passthrough_setparameter; + dev->startpage = filter->startpage?filter_startpage:passthrough_startpage; + dev->startclip = filter->startclip?filter_startclip:passthrough_startclip; + dev->endclip = filter->endclip?filter_endclip:passthrough_endclip; + dev->stroke = filter->stroke?filter_stroke:passthrough_stroke; + dev->fill = filter->fill?filter_fill:passthrough_fill; + dev->fillbitmap = filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap; + dev->fillgradient = filter->fillgradient?filter_fillgradient:passthrough_fillgradient; + dev->addfont = filter->addfont?filter_addfont:passthrough_addfont; + dev->drawchar = filter->drawchar?filter_drawchar:passthrough_drawchar; + dev->drawlink = filter->drawlink?filter_drawlink:passthrough_drawlink; + dev->endpage = filter->endpage?filter_endpage:passthrough_endpage; +} static gfxresult_t* twopass_finish(gfxdevice_t*dev) { internal_t*i = (internal_t*)dev->internal; - - assert(!strcmp(i->out->name, "record")); - + gfxresult_t*r; if(i->filter->finish) { r = i->filter->finish(i->filter, i->out); @@ -239,63 +279,164 @@ static gfxresult_t* twopass_finish(gfxdevice_t*dev) } if(i->pass == i->num_passes) { - /* this output device was not a record device, so we don't have - to do anything here (like cleanup) */ + free(i->twopass); + i->twopass = 0; + i->filter = 0; + free(i); + dev->internal=0; + free(dev); return r; } /* switch to next pass filter */ i->filter = &i->twopass->pass2; + setup_twopass(dev, i->filter); + dev->finish = twopass_finish; if(i->pass == i->num_passes-1) { /* we don't record in the final pass- we just stream out to the next output device */ i->out = i->final_out; } else { - // this only happens for 3 passes or more + // switch to a new tempfile- this only happens for 3 passes or more assert(i->num_passes>2); gfxdevice_record_init(&i->record, /*use tempfile*/1); i->out = &i->record; } i->pass++; - gfxresult_record_replay(r, i->out); - r = i->out->finish(i->out); + gfxresult_record_replay(r, dev); + r->destroy(r); - return r; + return twopass_finish(dev); } -gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*twopass, gfxdevice_t*out) +gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*_twopass, gfxdevice_t*out) { internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t)); + + gfxtwopassfilter_t*twopass = (gfxtwopassfilter_t*)rfx_alloc(sizeof(gfxtwopassfilter_t)); + memcpy(twopass, _twopass, sizeof(gfxtwopassfilter_t)); gfxdevice_record_init(&i->record, /*use tempfile*/1); i->out = &i->record; i->final_out = out; - i->filter = &twopass->pass1; i->twopass = twopass; i->pass = 1; i->num_passes = 2; - - dev->setparameter = i->filter->setparameter?filter_setparameter:passthrough_setparameter; - dev->startpage = i->filter->startpage?filter_startpage:passthrough_startpage; - dev->startclip = i->filter->startclip?filter_startclip:passthrough_startclip; - dev->endclip = i->filter->endclip?filter_endclip:passthrough_endclip; - dev->stroke = i->filter->stroke?filter_stroke:passthrough_stroke; - dev->fill = i->filter->fill?filter_fill:passthrough_fill; - dev->fillbitmap = i->filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap; - dev->fillgradient = i->filter->fillgradient?filter_fillgradient:passthrough_fillgradient; - dev->addfont = i->filter->addfont?filter_addfont:passthrough_addfont; - dev->drawchar = i->filter->drawchar?filter_drawchar:passthrough_drawchar; - dev->drawlink = i->filter->drawlink?filter_drawlink:passthrough_drawlink; - dev->endpage = i->filter->endpage?filter_endpage:passthrough_endpage; - dev->finish = twopass_finish; - + dev->internal = i; - dev->name = i->filter->name?i->filter->name:"filter"; + + i->filter = &twopass->pass1; + setup_twopass(dev, i->filter); dev->finish = twopass_finish; + 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; + assert(cmd); + 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, "vectors_to_glyphs")) { + f = malloc(sizeof(gfxtwopassfilter_t)); + gfxtwopassfilter_vectors_to_glyphs_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; + } +}