From a725c3e28bafaf52cc45bdacf730b80edd83756d Mon Sep 17 00:00:00 2001 From: Matthias Kramm Date: Fri, 26 Feb 2010 17:36:58 -0800 Subject: [PATCH] added filter support to ruby module --- lib/devices/record.c | 10 +- lib/filters/alpha.c | 2 +- ...e_font_transform.c => remove_font_transforms.c} | 6 +- lib/gfxfilter.c | 92 +++++++------ lib/gfxfilter.h | 22 ++++ lib/pdf/pdf.cc | 1 - lib/ruby/gfx.c | 135 +++++++++++++------- lib/ruby/test.rb | 6 +- src/pdf2swf.c | 1 + 9 files changed, 180 insertions(+), 95 deletions(-) rename lib/filters/{remove_font_transform.c => remove_font_transforms.c} (90%) diff --git a/lib/devices/record.c b/lib/devices/record.c index ae493ee..c8e4ffe 100644 --- a/lib/devices/record.c +++ b/lib/devices/record.c @@ -584,7 +584,7 @@ void gfxresult_record_replay(gfxresult_t*result, gfxdevice_t*device) internal_result_t*i = (internal_result_t*)result->internal; reader_t r; - if(i->filename) { + if(i->use_tempfile) { reader_init_filereader2(&r, i->filename); } else { reader_init_memreader(&r, i->data, i->length); @@ -633,6 +633,7 @@ static void record_result_destroy(gfxresult_t*r) free(i->data);i->data = 0; } if(i->filename) { + unlink(i->filename); free(i->filename); } free(r->internal);r->internal = 0; @@ -676,7 +677,8 @@ void gfxdevice_record_flush(gfxdevice_t*dev, gfxdevice_t*out) replay(dev, out, &r); writer_growmemwrite_reset(&i->w); } else { - msg(" Flushing not supported for file based record device"); + msg(" Flushing not supported for file based record device"); + exit(1); } } } @@ -698,10 +700,10 @@ static gfxresult_t* record_finish(struct _gfxdevice*dev) ir->use_tempfile = i->use_tempfile; if(i->use_tempfile) { + ir->filename = i->filename; + } else { ir->data = writer_growmemwrite_getmem(&i->w); ir->length = i->w.pos; - } else { - ir->filename = i->filename; } i->w.finish(&i->w); diff --git a/lib/filters/alpha.c b/lib/filters/alpha.c index 1dcd328..5178c48 100644 --- a/lib/filters/alpha.c +++ b/lib/filters/alpha.c @@ -99,7 +99,7 @@ static void maketransparent_fillgradient(gfxfilter_t*f, gfxline_t*line, gfxgradi gfxgradient_destroy(g); } -void gfxfilter_maketransparent(gfxfilter_t*f, U8 alpha) +void gfxfilter_maketransparent_init(gfxfilter_t*f, U8 alpha) { internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); i->alpha = alpha; diff --git a/lib/filters/remove_font_transform.c b/lib/filters/remove_font_transforms.c similarity index 90% rename from lib/filters/remove_font_transform.c rename to lib/filters/remove_font_transforms.c index 73bfe4d..914428f 100644 --- a/lib/filters/remove_font_transform.c +++ b/lib/filters/remove_font_transforms.c @@ -40,15 +40,15 @@ static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_ out->drawchar(out, font, glyphnr, color, matrix); } -void gfxfilter_normalizefonts(gfxtwopassfilter_t*f) +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->pass1.name = "remove font transform pass 1"; + f->pass1.name = "remove font transforms pass 1"; f->pass1.drawchar = pass1_drawchar; f->pass1.internal = i; - f->pass2.name = "remove font transform pass 2"; + f->pass2.name = "remove font transforms pass 2"; f->pass2.drawchar = pass2_drawchar; f->pass2.internal = i; } diff --git a/lib/gfxfilter.c b/lib/gfxfilter.c index c8cc253..7e182f7 100644 --- a/lib/gfxfilter.c +++ b/lib/gfxfilter.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include #include "mem.h" @@ -28,9 +29,9 @@ 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; @@ -100,7 +101,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; } @@ -166,13 +177,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) { @@ -216,10 +220,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; @@ -239,18 +245,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); @@ -259,20 +278,26 @@ 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; @@ -280,42 +305,33 @@ static gfxresult_t* twopass_finish(gfxdevice_t*dev) i->pass++; gfxresult_record_replay(r, i->out); - r = i->out->finish(i->out); + 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; } diff --git a/lib/gfxfilter.h b/lib/gfxfilter.h index 07c85c8..c34de38 100644 --- a/lib/gfxfilter.h +++ b/lib/gfxfilter.h @@ -22,6 +22,7 @@ #define __gfxfilter_h__ #include "gfxdevice.h" +#include "types.h" #ifdef __cplusplus extern "C" { @@ -46,6 +47,9 @@ typedef struct _gfxfilter void (*drawlink)(struct _gfxfilter*in, gfxline_t*line, const char*action, struct _gfxdevice*out); void (*endpage)(struct _gfxfilter*in, struct _gfxdevice*out); gfxresult_t* (*finish)(struct _gfxfilter*in, struct _gfxdevice*out); + + void (*dealloc)(struct _gfxfilter*f); + void* internal; } gfxfilter_t; @@ -58,6 +62,24 @@ typedef struct _gfxtwopassfilter gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*dev); gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*filter, gfxdevice_t*dev); +#define wrap_filter(dev, name, args...) \ + {gfxfilter_t f_##name; \ + gfxfilter_##name##_init(&f_##name, ## args); \ + dev = gfxfilter_apply(&f_##name, dev); \ + } + +#define wrap_filter2(dev, name, args...) \ + {gfxtwopassfilter_t f_##name; \ + gfxtwopassfilter_##name##_init(&f_##name, ## args); \ + dev = gfxtwopassfilter_apply(&f_##name, dev); \ + } + +/* known filters */ +void gfxfilter_maketransparent_init(gfxfilter_t*f, U8 alpha); +void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f); + +void check_filter(); + #ifdef __cplusplus } #endif diff --git a/lib/pdf/pdf.cc b/lib/pdf/pdf.cc index a5371c5..57382c4 100644 --- a/lib/pdf/pdf.cc +++ b/lib/pdf/pdf.cc @@ -442,7 +442,6 @@ static gfxdocument_t*pdf_open(gfxsource_t*src, const char*filename) delete userPW; } if (!i->doc->isOk()) { - printf("xpdf reports document as broken.\n"); return 0; } diff --git a/lib/ruby/gfx.c b/lib/ruby/gfx.c index d392ed0..ce11f02 100644 --- a/lib/ruby/gfx.c +++ b/lib/ruby/gfx.c @@ -4,6 +4,7 @@ #include "../gfxtools.h" #include "../gfximage.h" #include "../gfxfont.h" +#include "../gfxfilter.h" #include "../devices/pdf.h" #include "../readers/swf.h" #include "../readers/image.h" @@ -11,6 +12,7 @@ #include "../mem.h" #include "../types.h" #include "../log.h" +#include "../args.h" #define RUBY_GFX_VERSION "0.9.0" @@ -121,7 +123,10 @@ static void doc_mark(doc_internal_t*doc) static void doc_free(doc_internal_t*doc) { gfxfontlist_free(doc->fontlist, 0); - doc->doc->destroy(doc->doc); + if(doc->doc) { + doc->doc->destroy(doc->doc); + } + doc->doc = 0; free(doc); } @@ -421,6 +426,8 @@ static ID id_line = 0; static ID id_spline = 0; static ID id_radial = 0; static ID id_linear = 0; +static ID id_remove_font_transforms = 0; +static ID id_maketransparent = 0; static VALUE noop(int argc, VALUE *argv, VALUE obj) {return obj;} @@ -616,39 +623,46 @@ void rb_endpage(gfxdevice_t*dev) HEAD forward(v, id_endpage, 0); } +void gfxresult_rb_destroy(gfxresult_t*r) +{ + free(r); +} gfxresult_t* rb_finish(gfxdevice_t*dev) { HEAD - VALUE ret = forward(v, id_endpage, 0); + VALUE ret = forward(v, id_finish, 0); gfxresult_t*r = (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t)); + r->destroy = gfxresult_rb_destroy; r->internal = (void*)(ptroff_t)ret; return r; } +#define make_device(dev, idoc, device) \ + gfxdevice_t dev; \ + device_internal_t i; \ + i.v = device; \ + i.doc = idoc; \ + dev.internal = &i; \ + dev.setparameter = rb_setparameter; \ + dev.startpage = rb_startpage; \ + dev.startclip = rb_startclip; \ + dev.endclip = rb_endclip; \ + dev.stroke = rb_stroke; \ + dev.fill = rb_fill; \ + dev.fillbitmap = rb_fillbitmap; \ + dev.fillgradient = rb_fillgradient; \ + dev.addfont = rb_addfont; \ + dev.drawchar = rb_drawchar; \ + dev.drawlink = rb_drawlink; \ + dev.endpage = rb_endpage; \ + dev.finish = rb_finish; + static VALUE page_render(VALUE cls, VALUE device) { Check_Type(device, T_OBJECT); Get_Page(page,cls) - gfxdevice_t dev; - device_internal_t i; - i.v = device; - i.doc = page->doc; - - dev.internal = &i; - dev.setparameter = rb_setparameter; - dev.startpage = rb_startpage; - dev.startclip = rb_startclip; - dev.endclip = rb_endclip; - dev.stroke = rb_stroke; - dev.fill = rb_fill; - dev.fillbitmap = rb_fillbitmap; - dev.fillgradient = rb_fillgradient; - dev.addfont = rb_addfont; - dev.drawchar = rb_drawchar; - dev.drawlink = rb_drawlink; - dev.endpage = rb_endpage; - dev.finish = rb_finish; + make_device(dev, page->doc, device); dev.startpage(&dev, page->page->width, page->page->height); page->page->render(page->page, &dev); @@ -657,30 +671,63 @@ static VALUE page_render(VALUE cls, VALUE device) return cls; } -static VALUE doc_prepare(VALUE cls, VALUE device) +static VALUE doc_render(VALUE cls, VALUE device, VALUE _range, VALUE filters) { + const char*range = 0; + if(!NIL_P(_range)) { + Check_Type(_range, T_STRING); + range = StringValuePtr(_range); + } Get_Doc(doc,cls); - gfxdevice_t dev; - device_internal_t i; - i.v = device; - i.doc = doc; - - dev.internal = &i; - dev.setparameter = rb_setparameter; - dev.startpage = rb_startpage; - dev.startclip = rb_startclip; - dev.endclip = rb_endclip; - dev.stroke = rb_stroke; - dev.fill = rb_fill; - dev.fillbitmap = rb_fillbitmap; - dev.fillgradient = rb_fillgradient; - dev.addfont = rb_addfont; - dev.drawchar = rb_drawchar; - dev.drawlink = rb_drawlink; - dev.endpage = rb_endpage; - dev.finish = rb_finish; + make_device(_dev, doc, device); + gfxdevice_t*dev = &_dev; + + if(!NIL_P(filters)) { + if(TYPE(filters) != T_ARRAY) + rb_raise(rb_eArgError, "third argument of doc->render must be an array of symbols"); + + int len = RARRAY(filters)->len; + int t=0; + while(tptr[t++]; + Check_Type(filter, T_SYMBOL); + ID id = SYM2ID(filter); +# define PARAM(x) VALUE x;if(t==len) rb_raise(rb_eArgError, "End of array while parsing arguments for filter %s", rb_id2name(id)); \ + else x = RARRAY(filters)->ptr[t++]; + if(id == id_remove_font_transforms) { + wrap_filter2(dev, remove_font_transforms); + } else if(id == id_maketransparent) { + PARAM(alpha); + wrap_filter(dev, maketransparent, FIX2INT(alpha)); + } else { + rb_raise(rb_eArgError, "unknown filter %s", rb_id2name(id)); + } + } + } + + int pagenr; + for(pagenr=1;pagenr<=doc->doc->num_pages;pagenr++) { + if(is_in_range(pagenr, (char*)range)) { + gfxpage_t*page = doc->doc->getpage(doc->doc, pagenr); + dev->startpage(dev, page->width, page->height); + page->render(page, dev); + dev->endpage(dev); + page->destroy(page); + } + } + + + gfxresult_t*r = dev->finish(dev); + r->destroy(r); + + return Qnil; +} +static VALUE doc_prepare(VALUE cls, VALUE device) +{ + Get_Doc(doc,cls); + make_device(dev, doc, device); doc->doc->prepare(doc->doc, &dev); return cls; } @@ -724,6 +771,7 @@ void Init_gfx() rb_define_method(Document, "page", doc_get_page, 1); rb_define_method(Document, "each_page", doc_each_page, 0); rb_define_method(Document, "prepare", doc_prepare, 1); + rb_define_method(Document, "render", doc_render, 3); Bitmap = rb_define_class_under(GFX, "Bitmap", rb_cObject); rb_define_method(Bitmap, "save_jpeg", image_save_jpeg, 2); @@ -760,7 +808,6 @@ void Init_gfx() rb_define_method(Device, "addfont", noop, -1); rb_define_method(Device, "drawchar", noop, -1); rb_define_method(Device, "drawlink", noop, -1); - rb_define_method(Device, "endpage", noop, -1); PDFClass = rb_define_class_under(GFX, "PDF", Document); rb_define_alloc_func(PDFClass, pdf_allocate); @@ -770,7 +817,7 @@ void Init_gfx() ImageClass = rb_define_class_under(GFX, "ImageRead", Document); rb_define_alloc_func(ImageClass, imgdrv_allocate); - + id_setparameter = rb_intern("setparameter"); id_startpage = rb_intern("startpage") ; id_startclip = rb_intern("startclip") ; @@ -795,5 +842,7 @@ void Init_gfx() id_spline = rb_intern("spline"); id_radial = rb_intern("radial"); id_linear = rb_intern("linear"); + id_remove_font_transforms = rb_intern("remove_font_transforms"); + id_maketransparent = rb_intern("maketransparent"); } diff --git a/lib/ruby/test.rb b/lib/ruby/test.rb index afccbc9..fa411e2 100644 --- a/lib/ruby/test.rb +++ b/lib/ruby/test.rb @@ -40,10 +40,6 @@ class TestRender < GFX::Device end pdf = GFX::PDF.new('abcdef.pdf') - r = TestRender.new -pdf.each_page do |page| - puts "#{page.nr} #{page.width}x#{page.height}" - page.render(r) -end +pdf.render(r, "1-5", [:remove_font_transforms]) diff --git a/src/pdf2swf.c b/src/pdf2swf.c index 4f82dfc..c7a804e 100644 --- a/src/pdf2swf.c +++ b/src/pdf2swf.c @@ -43,6 +43,7 @@ #include "../lib/devices/polyops.h" #include "../lib/devices/record.h" #include "../lib/devices/rescale.h" +#include "../lib/gfxfilter.h" #include "../lib/pdf/pdf.h" #include "../lib/log.h" -- 1.7.10.4