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);
free(i->data);i->data = 0;
}
if(i->filename) {
+ unlink(i->filename);
free(i->filename);
}
free(r->internal);r->internal = 0;
replay(dev, out, &r);
writer_growmemwrite_reset(&i->w);
} else {
- msg("<error> Flushing not supported for file based record device");
+ msg("<fatal> Flushing not supported for file based record device");
+ exit(1);
}
}
}
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);
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;
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;
}
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "mem.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;
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;
}
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)
{
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;
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);
}
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);
+ 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;
}
#define __gfxfilter_h__
#include "gfxdevice.h"
+#include "types.h"
#ifdef __cplusplus
extern "C" {
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;
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
delete userPW;
}
if (!i->doc->isOk()) {
- printf("xpdf reports document as broken.\n");
return 0;
}
#include "../gfxtools.h"
#include "../gfximage.h"
#include "../gfxfont.h"
+#include "../gfxfilter.h"
#include "../devices/pdf.h"
#include "../readers/swf.h"
#include "../readers/image.h"
#include "../mem.h"
#include "../types.h"
#include "../log.h"
+#include "../args.h"
#define RUBY_GFX_VERSION "0.9.0"
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);
}
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;}
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);
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(t<len) {
+ VALUE filter = RARRAY(filters)->ptr[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;
}
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);
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);
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") ;
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");
}
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])
#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"