started implementing 'passthrough' device
[swftools.git] / lib / python / gfx.c
1 /* gfx.c
2
3    Python wrapper for gfx convert
4
5    Part of the swftools package.
6
7    Copyright (c) 2003 Matthias Kramm <kramm@quiss.org>
8  
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
22
23 #include <Python.h>
24 #include <stdarg.h>
25 #undef HAVE_STAT
26 #include "../devices/swf.h"
27 #include "../devices/render.h"
28 #include "../devices/rescale.h"
29 #include "../devices/text.h"
30 #include "../pdf/pdf.h"
31 #include "../log.h"
32 #include "../utf8.h"
33
34 gfxsource_t*pdfdriver;
35
36 staticforward PyTypeObject OutputClass;
37 staticforward PyTypeObject PageClass;
38 staticforward PyTypeObject DriverClass;
39
40 typedef struct {
41     PyObject_HEAD
42     gfxdevice_t*output_device;
43     PyObject*pyobj; //only for passthrough
44 } OutputObject;
45
46 typedef struct {
47     PyObject_HEAD
48     PyObject*parent;
49     gfxpage_t*page;
50     int nr;
51 } PageObject;
52
53 typedef struct {
54     PyObject_HEAD
55     gfxdocument_t*doc;
56     char*filename;
57 } DocObject;
58
59 static char* strf(char*format, ...)
60 {
61     char buf[1024];
62     int l;
63     va_list arglist;
64     va_start(arglist, format);
65     vsprintf(buf, format, arglist);
66     va_end(arglist);
67     return strdup(buf);
68 }
69 #define PY_ERROR(s,args...) (PyErr_SetString(PyExc_Exception, strf(s, ## args)),NULL)
70 #define PY_NONE Py_BuildValue("s", 0)
71
72 //---------------------------------------------------------------------
73 staticforward PyObject* output_save(PyObject* _self, PyObject* args, PyObject* kwargs);
74 staticforward PyObject* output_startpage(PyObject* _self, PyObject* args, PyObject* kwargs);
75 staticforward PyObject* output_endpage(PyObject* _self, PyObject* args, PyObject* kwargs);
76
77 static PyMethodDef output_methods[] =
78 {
79     /* Output functions */
80     {"save", (PyCFunction)output_save, METH_KEYWORDS, ""},
81     {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, ""},
82     {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, ""},
83     {0,0,0,0}
84 };
85 static PyObject* output_save(PyObject* _self, PyObject* args, PyObject* kwargs)
86 {
87     OutputObject* self = (OutputObject*)_self;
88     char*filename = 0;
89     static char *kwlist[] = {"filename", NULL};
90     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
91         return NULL;
92
93     gfxresult_t*result = self->output_device->finish(self->output_device);
94     self->output_device = 0;
95     if(result->save(result, filename) < 0) {
96         return PY_ERROR("Couldn't write to %s", filename);
97     }
98     result->destroy(result);
99     return PY_NONE;
100 }
101 static PyObject* output_startpage(PyObject* _self, PyObject* args, PyObject* kwargs)
102 {
103     OutputObject* self = (OutputObject*)_self;
104     int width=0, height=0;
105     if (!PyArg_ParseTuple(args, "ii", &width, &height))
106         return NULL;
107     self->output_device->startpage(self->output_device, width, height);
108     return PY_NONE;
109 }
110 static PyObject* output_endpage(PyObject* _self, PyObject* args, PyObject* kwargs)
111 {
112     OutputObject* self = (OutputObject*)_self;
113     if (!PyArg_ParseTuple(args, ""))
114         return NULL;
115     self->output_device->endpage(self->output_device);
116     return PY_NONE;
117 }
118 static PyObject* f_createSWF(PyObject* parent, PyObject* args, PyObject* kwargs)
119 {
120     static char *kwlist[] = {NULL};
121     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
122         return NULL;
123     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
124     
125     self->output_device = malloc(sizeof(gfxdevice_t));
126     gfxdevice_swf_init(self->output_device);
127     return (PyObject*)self;
128 }
129 static PyObject* f_createImageList(PyObject* parent, PyObject* args, PyObject* kwargs)
130 {
131     static char *kwlist[] = {NULL};
132     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
133         return NULL;
134     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
135     
136     self->output_device = malloc(sizeof(gfxdevice_t));
137     gfxdevice_render_init(self->output_device);
138     return (PyObject*)self;
139 }
140 static PyObject* f_createPlainText(PyObject* parent, PyObject* args, PyObject* kwargs)
141 {
142     static char *kwlist[] = {NULL};
143     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
144         return NULL;
145     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
146     
147     self->output_device = malloc(sizeof(gfxdevice_t));
148     gfxdevice_text_init(self->output_device);
149     return (PyObject*)self;
150 }
151
152 static PyObject*callback_python(char*function, gfxdevice_t*dev, const char*format, ...)
153 {
154     OutputObject*self = (OutputObject*)dev->internal;
155     
156     if(!PyObject_HasAttrString(self->pyobj, function))
157         return PY_NONE;
158
159     va_list ap;
160     va_start(ap, format);
161
162     PyObject*tuple = PyTuple_New(strlen(format));
163     int pos = 0;
164     while(format[pos]) {
165         char p = format[pos];
166         if(p=='s') {
167             char*s = va_arg(ap, char*);
168             PyTuple_SetItem(tuple, pos, PyString_FromString(s));
169         } else if(p=='i') {
170             int i = va_arg(ap, int);
171             PyTuple_SetItem(tuple, pos, PyInt_FromLong(i));
172         } else if(p=='c') {
173             void* ptr = va_arg(ap, void*);
174             gfxcolor_t*col = (gfxcolor_t*)ptr;
175             PyObject*colobj = PyTuple_New(4);
176             PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->r));
177             PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->g));
178             PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->b));
179             PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->a));
180             PyTuple_SetItem(tuple, pos, colobj);
181         } else if(p=='l') {
182             void* ptr = va_arg(ap, void*);
183             gfxline_t*line = (gfxline_t*)ptr;
184             gfxline_t*l;
185             int len = 0, i = 0;
186             l = line;
187             while(l) {l=l->next;len++;}
188             PyObject*list = PyList_New(len);
189             l = line;
190             while(l) {
191                 PyObject*point=0;
192                 if(l->type == gfx_moveTo) {
193                     point = PyTuple_New(3);
194                     PyTuple_SetItem(point, 0, PyString_FromString("m"));
195                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
196                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
197                 } else if(l->type == gfx_lineTo) {
198                     point = PyTuple_New(3);
199                     PyTuple_SetItem(point, 0, PyString_FromString("l"));
200                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
201                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
202                 } else if(l->type == gfx_splineTo) {
203                     point = PyTuple_New(5);
204                     PyTuple_SetItem(point, 0, PyString_FromString("l"));
205                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
206                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
207                     PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sy));
208                     PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
209                 } else {
210                     point = PY_NONE;
211                 }
212                 PyList_SetItem(list, i, point);
213                 l = l->next;
214                 i++;
215             }
216             PyTuple_SetItem(tuple, pos, list);
217         } else {
218             PyTuple_SetItem(tuple, pos, PY_NONE);
219         }
220         pos++;
221     }
222     va_end(ap);
223     PyObject*f = PyObject_GetAttrString(self->pyobj, function);
224     if(!f)
225         return 0;
226     PyErr_Clear();
227     PyObject* result = PyObject_CallObject(f, tuple);
228
229     if(!result)  // should we do some error handling here?
230         return 0;
231
232     Py_DECREF(result);
233     return 0;
234 }
235     
236 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
237 {
238     callback_python("setparameter", dev, "ss", key, value);
239     return 1;
240 }
241 static void my_startpage(gfxdevice_t*dev, int width, int height)
242 {
243     callback_python("startpage", dev, "ii", width, height);
244 }
245 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
246 {
247     callback_python("startclip", dev, "l", line);
248 }
249 static void my_endclip(gfxdevice_t*dev)
250 {
251     callback_python("endclip", dev, "");
252 }
253 static void my_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
254 {
255     char*cap = 0;
256     char*joint = 0;
257     if(cap_style == gfx_capButt)
258         cap = "butt";
259     else if(cap_style == gfx_capRound)
260         cap = "round";
261     else if(cap_style == gfx_capSquare)
262         cap = "square";
263     if(joint_style == gfx_joinMiter)
264         joint = "miter";
265     else if(joint_style == gfx_joinRound)
266         joint = "round";
267     else if(joint_style == gfx_joinBevel)
268         joint = "bevel";
269     callback_python("stroke", dev, "licssi", line, width, color, cap, joint, miterLimit);
270 }
271 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
272 {
273     callback_python("fill", dev, "lc", line, color);
274 }
275 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
276 {
277     callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
278 }
279 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
280 {
281     callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
282 }
283 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
284 {
285     callback_python("addfont", dev, "f", font);
286 }
287 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
288 {
289     callback_python("drawchar", dev, "ficm", font, glyph, color, matrix);
290 }
291 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
292 {
293     callback_python("drawlink", dev, "ls", line, action);
294 }
295 static void my_endpage(gfxdevice_t*dev)
296 {
297     callback_python("drawlink", dev, "");
298 }
299 static gfxresult_t* my_finish(gfxdevice_t*dev)
300 {
301     callback_python("finish", dev, "");
302     return 0;
303 }
304
305 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
306 {
307     static char *kwlist[] = {"device", NULL};
308     PyObject*obj;
309     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
310         return NULL;
311     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
312    
313     self->pyobj = obj;
314     self->output_device = malloc(sizeof(gfxdevice_t));
315     memset(self->output_device, 0, sizeof(gfxdevice_t));
316     self->output_device->name = strdup("passthrough");
317
318     self->output_device->setparameter = my_setparameter;
319     self->output_device->startpage = my_startpage;
320     self->output_device->startclip = my_startclip;
321     self->output_device->addfont = my_addfont;
322     self->output_device->endclip = my_endclip;
323     self->output_device->stroke = my_stroke;
324     self->output_device->fill = my_fill;
325     self->output_device->fillbitmap = my_fillbitmap;
326     self->output_device->fillgradient = my_fillgradient;
327     self->output_device->drawchar = my_drawchar;
328     self->output_device->drawlink = my_drawlink;
329     self->output_device->endpage = my_endpage;
330     self->output_device->finish = my_finish;
331     self->output_device->internal = self;
332
333     return (PyObject*)self;
334 }
335
336
337 static void output_dealloc(PyObject* _self) {
338     OutputObject* self = (OutputObject*)_self;
339
340     if(self->output_device) {
341         gfxresult_t*result = self->output_device->finish(self->output_device);
342         if(result) {
343             result->destroy(result);result=0;
344         }
345         self->output_device = 0;
346     }
347     
348     PyObject_Del(self);
349 }
350 static PyObject* output_getattr(PyObject * _self, char* a)
351 {
352     OutputObject*self = (OutputObject*)_self;
353     
354 /*    if(!strcmp(a, "x1")) {
355         return PyInt_FromLong(self->output_device->x1);
356     } else if(!strcmp(a, "y1")) {
357         return PyInt_FromLong(self->output_device->y1);
358     } else if(!strcmp(a, "x2")) {
359         return PyInt_FromLong(self->output_device->x2);
360     } else if(!strcmp(a, "y2")) {
361         return PyInt_FromLong(self->output_device->y2);
362     }*/
363     
364     return Py_FindMethod(output_methods, _self, a);
365 }
366 static int output_setattr(PyObject * _self, char* a, PyObject * o) 
367 {
368     OutputObject*self = (OutputObject*)_self;
369     if(!PyString_Check(o))
370         return -1;
371     char*value = PyString_AsString(o);
372     self->output_device->setparameter(self->output_device, a, value);
373     return -1;
374 }
375 static int output_print(PyObject * _self, FILE *fi, int flags)
376 {
377     OutputObject*self = (OutputObject*)_self;
378     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
379     return 0;
380 }
381
382 //---------------------------------------------------------------------
383 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
384 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
385
386 static PyMethodDef page_methods[] =
387 {
388     /* Page functions */
389     {"render", (PyCFunction)page_render, METH_KEYWORDS, ""},
390     {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, ""},
391     {0,0,0,0}
392 };
393 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
394 {
395     PageObject* self = (PageObject*)_self; 
396     
397     static char *kwlist[] = {"dev", "move", "clip", NULL};
398     OutputObject*output = 0;
399     PyObject*move=0;
400     PyObject*clip=0;
401     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
402                 &move,&clip
403                 ))
404         return NULL;
405
406     int x=0,y=0;
407     int cx1=0,cy1=0,cx2=0,cy2=0;
408
409     if(move) {
410         if (!PyArg_ParseTuple(move, "ii", &x,&y))
411             return NULL;
412     }
413     if(clip) {
414         if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
415             return NULL;
416     }
417
418     if(x|y|cx1|cx2|cy1|cy2)
419         self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
420     else
421         self->page->render(self->page, output->output_device);
422     return PY_NONE;
423 }
424
425 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
426 {
427     PageObject* self = (PageObject*)_self; 
428     
429     static char *kwlist[] = {"width", "height", NULL};
430     int width=0,height=0;
431     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
432         return NULL;
433
434     if(!width || !height) {
435         return PY_ERROR("invalid dimensions: %dx%d", width,height);
436     }
437
438     gfxdevice_t dev1,dev2;
439     gfxdevice_render_init(&dev1);
440     dev1.setparameter(&dev1, "antialise", "2");
441     gfxdevice_rescale_init(&dev2, &dev1, width, height);
442     dev2.startpage(&dev2, self->page->width, self->page->height);
443     self->page->render(self->page, &dev2);
444     dev2.endpage(&dev2);
445     gfxresult_t*result = dev2.finish(&dev2);
446     gfximage_t*img = (gfximage_t*)result->get(result,"page0");
447     int l = img->width*img->height;
448     unsigned char*data = malloc(img->width*img->height*3);
449     int s,t;
450     for(t=0,s=0;t<l;s+=3,t++) {
451         data[s+0] = img->data[t].r;
452         data[s+1] = img->data[t].g;
453         data[s+2] = img->data[t].b;
454     }
455     result->destroy(result);
456     return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
457 }
458
459 static void page_dealloc(PyObject* _self) {
460     PageObject* self = (PageObject*)_self; 
461     if(self->page) {
462         self->page->destroy(self->page);
463         self->page=0;
464     }
465     if(self->parent) {
466         Py_DECREF(self->parent);
467         self->parent=0;
468     }
469     
470     PyObject_Del(self);
471 }
472 static PyObject* page_getattr(PyObject * _self, char* a)
473 {
474     PageObject*self = (PageObject*)_self;
475     
476     if(!strcmp(a, "size")) {
477         return Py_BuildValue("(ii)", self->page->width, self->page->height);
478     } if(!strcmp(a, "doc")) {
479         Py_INCREF(self->parent);
480         return self->parent;
481     } if(!strcmp(a, "nr")) {
482         return PyInt_FromLong(self->nr);
483     } else if(!strcmp(a, "width")) {
484         return PyInt_FromLong(self->page->width);
485     } else if(!strcmp(a, "height")) {
486         return PyInt_FromLong(self->page->height);
487     }
488     return Py_FindMethod(page_methods, _self, a);
489 }
490 static int page_setattr(PyObject * self, char* a, PyObject * o) {
491     return -1;
492 }
493 static int page_print(PyObject * _self, FILE *fi, int flags)
494 {
495     PageObject*self = (PageObject*)_self;
496     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
497     return 0;
498 }
499
500 //---------------------------------------------------------------------
501
502 staticforward PyObject* doc_getPage(PyObject* parent, PyObject* args, PyObject* kwargs);
503 staticforward PyObject* doc_getInfo(PyObject* parent, PyObject* args, PyObject* kwargs);
504 staticforward PyObject* doc_setParameter(PyObject* parent, PyObject* args, PyObject* kwargs);
505
506 static PyMethodDef doc_methods[] =
507 {
508     /* PDF functions */
509     {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, ""},
510     {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, ""},
511     {"setParameter", (PyCFunction)doc_setParameter, METH_KEYWORDS, ""},
512     {0,0,0,0}
513 };
514
515 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
516 {
517     DocObject* self = (DocObject*)_self;
518
519     static char *kwlist[] = {"nr", NULL};
520     int pagenr = 0;
521     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
522         return NULL;
523
524     PageObject*page = PyObject_New(PageObject, &PageClass);
525     page->page = self->doc->getpage(self->doc, pagenr);
526     page->nr = pagenr;
527     page->parent = _self;
528     Py_INCREF(page->parent);
529     if(!page->page) {
530         PyObject_Del(page);
531         return PY_ERROR("Couldn't extract page %d", pagenr);
532     }
533     return (PyObject*)page;
534 }
535
536 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
537 {
538     DocObject* self = (DocObject*)_self;
539
540     static char *kwlist[] = {"key", NULL};
541     char*key = 0;
542     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
543         return NULL;
544
545     char*s = self->doc->getinfo(self->doc, key);
546     return PyString_FromString(s);
547 }
548
549 static PyObject* doc_setParameter(PyObject* _self, PyObject* args, PyObject* kwargs)
550 {
551     DocObject* self = (DocObject*)_self;
552
553     static char *kwlist[] = {"key", "value", NULL};
554     char*key = 0, *value=0;
555     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
556         return NULL;
557
558     self->doc->set_parameter(self->doc, key, value);
559     return PY_NONE;
560 }
561
562 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
563 {
564     static char *kwlist[] = {"type", "filename", NULL};
565     char*filename;
566     char*type;
567     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename))
568         return NULL;
569
570     DocObject*self = PyObject_New(DocObject, &DriverClass);
571    
572     if(!strcmp(type,"pdf"))
573         self->doc = pdfdriver->open(pdfdriver,filename);
574     else
575         return PY_ERROR("Unknown type %s", type);
576
577     if(!self->doc) {
578         PyObject_Del(self);
579         return PY_ERROR("Couldn't open %s", filename);
580     }
581     self->filename = strdup(filename);
582     return (PyObject*)self;
583 }
584 static void doc_dealloc(PyObject* _self) {
585     DocObject* self = (DocObject*)_self;
586     if(self->doc) {
587         self->doc->destroy(self->doc);
588         self->doc=0;
589     }
590     if(self->filename) {
591         free(self->filename);self->filename=0;
592     }
593     PyObject_Del(self);
594 }
595 static PyObject* doc_getattr(PyObject * _self, char* a)
596 {
597     DocObject*self = (DocObject*)_self;
598     if(!strcmp(a, "pages")) {
599         return PyInt_FromLong(self->doc->num_pages);
600     }
601     if(!strcmp(a, "filename")) {
602         return PyString_FromString(self->filename);
603     }
604     return Py_FindMethod(doc_methods, _self, a);
605 }
606 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
607     return -1;
608 }
609 static int doc_print(PyObject * _self, FILE *fi, int flags)
610 {
611     DocObject*self = (DocObject*)_self;
612     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
613     return 0;
614 }
615
616 //---------------------------------------------------------------------
617
618 static PyTypeObject OutputClass =
619 {
620     PyObject_HEAD_INIT(NULL)
621     0,
622     tp_name: "Output",
623     tp_basicsize: sizeof(OutputObject),
624     tp_itemsize: 0,
625     tp_dealloc: output_dealloc,
626     tp_print: output_print,
627     tp_getattr: output_getattr,
628     tp_setattr: output_setattr,
629 };
630 static PyTypeObject PageClass =
631 {
632     PyObject_HEAD_INIT(NULL)
633     0,
634     tp_name: "Page",
635     tp_basicsize: sizeof(PageObject),
636     tp_itemsize: 0,
637     tp_dealloc: page_dealloc,
638     tp_print: page_print,
639     tp_getattr: page_getattr,
640     tp_setattr: page_setattr,
641 };
642 static PyTypeObject DriverClass =
643 {
644     PyObject_HEAD_INIT(NULL)
645     0,
646     tp_name: "PDF",
647     tp_basicsize: sizeof(DocObject),
648     tp_itemsize: 0,
649     tp_dealloc: doc_dealloc,
650     tp_print: doc_print,
651     tp_getattr: doc_getattr,
652     tp_setattr: doc_setattr,
653 };
654
655 //=====================================================================
656
657 static PyObject* f_setoption(PyObject* self, PyObject* args, PyObject* kwargs)
658 {
659     static char *kwlist[] = {"key", "value", NULL};
660     char*key=0,*value=0;
661     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
662         return NULL;
663     pdfdriver->set_parameter(pdfdriver,key,value);
664     return PY_NONE;
665 }
666
667 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
668 {
669     static char *kwlist[] = {"val", NULL};
670     int val;
671     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
672         return NULL;
673     setConsoleLogging(val);
674     return PY_NONE;
675 }
676
677 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
678 {
679     static char *kwlist[] = {"filename", NULL};
680     char*filename=0;
681     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
682         return NULL;
683     pdfdriver->set_parameter(pdfdriver,"font", filename);
684     return PY_NONE;
685 }
686
687 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
688 {
689     static char *kwlist[] = {"filename", NULL};
690     char*filename=0;
691     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
692         return NULL;
693     pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
694     return PY_NONE;
695 }
696
697 static PyMethodDef pdf2swf_methods[] =
698 {
699     /* sources */
700     {"open", (PyCFunction)f_open, METH_KEYWORDS, ""},
701     {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, ""},
702     {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, ""},
703     {"setoption", (PyCFunction)f_setoption, METH_KEYWORDS, ""},
704     {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, ""},
705
706     /* devices */
707     {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, ""},
708     {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, ""},
709     {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, ""},
710     {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, ""},
711
712     /* sentinel */
713     {0, 0, 0, 0}
714 };
715
716 void initgfx(void)
717 {
718     initLog(0,0,0,0,0,2);
719     OutputClass.ob_type = &PyType_Type;
720     PageClass.ob_type = &PyType_Type;
721     DriverClass.ob_type = &PyType_Type;
722  
723     pdfdriver = gfxsource_pdf_create();
724     
725     PyObject*module = Py_InitModule("gfx", pdf2swf_methods);
726 }