fixed some bugs
[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("s"));
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->sx));
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) { 
230         PyErr_Print();
231         PyErr_Clear();
232         return 0;
233     } else {
234         Py_DECREF(result);
235         return 0;
236     }
237 }
238     
239 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
240 {
241     callback_python("setparameter", dev, "ss", key, value);
242     return 1;
243 }
244 static void my_startpage(gfxdevice_t*dev, int width, int height)
245 {
246     callback_python("startpage", dev, "ii", width, height);
247 }
248 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
249 {
250     callback_python("startclip", dev, "l", line);
251 }
252 static void my_endclip(gfxdevice_t*dev)
253 {
254     callback_python("endclip", dev, "");
255 }
256 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)
257 {
258     char*cap = 0;
259     char*joint = 0;
260     if(cap_style == gfx_capButt)
261         cap = "butt";
262     else if(cap_style == gfx_capRound)
263         cap = "round";
264     else if(cap_style == gfx_capSquare)
265         cap = "square";
266     if(joint_style == gfx_joinMiter)
267         joint = "miter";
268     else if(joint_style == gfx_joinRound)
269         joint = "round";
270     else if(joint_style == gfx_joinBevel)
271         joint = "bevel";
272     callback_python("stroke", dev, "licssi", line, width, color, cap, joint, miterLimit);
273 }
274 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
275 {
276     callback_python("fill", dev, "lc", line, color);
277 }
278 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
279 {
280     callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
281 }
282 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
283 {
284     callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
285 }
286 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
287 {
288     callback_python("addfont", dev, "f", font);
289 }
290 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
291 {
292     callback_python("drawchar", dev, "ficm", font, glyph, color, matrix);
293 }
294 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
295 {
296     callback_python("drawlink", dev, "ls", line, action);
297 }
298 static void my_endpage(gfxdevice_t*dev)
299 {
300     callback_python("drawlink", dev, "");
301 }
302 static gfxresult_t* my_finish(gfxdevice_t*dev)
303 {
304     callback_python("finish", dev, "");
305     return 0;
306 }
307
308 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
309 {
310     static char *kwlist[] = {"device", NULL};
311     PyObject*obj;
312     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
313         return NULL;
314     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
315    
316     self->pyobj = obj;
317     self->output_device = malloc(sizeof(gfxdevice_t));
318     memset(self->output_device, 0, sizeof(gfxdevice_t));
319     self->output_device->name = strdup("passthrough");
320
321     self->output_device->setparameter = my_setparameter;
322     self->output_device->startpage = my_startpage;
323     self->output_device->startclip = my_startclip;
324     self->output_device->addfont = my_addfont;
325     self->output_device->endclip = my_endclip;
326     self->output_device->stroke = my_stroke;
327     self->output_device->fill = my_fill;
328     self->output_device->fillbitmap = my_fillbitmap;
329     self->output_device->fillgradient = my_fillgradient;
330     self->output_device->drawchar = my_drawchar;
331     self->output_device->drawlink = my_drawlink;
332     self->output_device->endpage = my_endpage;
333     self->output_device->finish = my_finish;
334     self->output_device->internal = self;
335
336     return (PyObject*)self;
337 }
338
339
340 static void output_dealloc(PyObject* _self) {
341     OutputObject* self = (OutputObject*)_self;
342
343     if(self->output_device) {
344         gfxresult_t*result = self->output_device->finish(self->output_device);
345         if(result) {
346             result->destroy(result);result=0;
347         }
348         self->output_device = 0;
349     }
350     
351     PyObject_Del(self);
352 }
353 static PyObject* output_getattr(PyObject * _self, char* a)
354 {
355     OutputObject*self = (OutputObject*)_self;
356     
357 /*    if(!strcmp(a, "x1")) {
358         return PyInt_FromLong(self->output_device->x1);
359     } else if(!strcmp(a, "y1")) {
360         return PyInt_FromLong(self->output_device->y1);
361     } else if(!strcmp(a, "x2")) {
362         return PyInt_FromLong(self->output_device->x2);
363     } else if(!strcmp(a, "y2")) {
364         return PyInt_FromLong(self->output_device->y2);
365     }*/
366     
367     return Py_FindMethod(output_methods, _self, a);
368 }
369 static int output_setattr(PyObject * _self, char* a, PyObject * o) 
370 {
371     OutputObject*self = (OutputObject*)_self;
372     if(!PyString_Check(o))
373         return -1;
374     char*value = PyString_AsString(o);
375     self->output_device->setparameter(self->output_device, a, value);
376     return -1;
377 }
378 static int output_print(PyObject * _self, FILE *fi, int flags)
379 {
380     OutputObject*self = (OutputObject*)_self;
381     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
382     return 0;
383 }
384
385 //---------------------------------------------------------------------
386 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
387 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
388
389 static PyMethodDef page_methods[] =
390 {
391     /* Page functions */
392     {"render", (PyCFunction)page_render, METH_KEYWORDS, ""},
393     {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, ""},
394     {0,0,0,0}
395 };
396 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
397 {
398     PageObject* self = (PageObject*)_self; 
399     
400     static char *kwlist[] = {"dev", "move", "clip", NULL};
401     OutputObject*output = 0;
402     PyObject*move=0;
403     PyObject*clip=0;
404     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
405                 &move,&clip
406                 ))
407         return NULL;
408
409     int x=0,y=0;
410     int cx1=0,cy1=0,cx2=0,cy2=0;
411
412     if(move) {
413         if (!PyArg_ParseTuple(move, "ii", &x,&y))
414             return NULL;
415     }
416     if(clip) {
417         if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
418             return NULL;
419     }
420
421     if(x|y|cx1|cx2|cy1|cy2)
422         self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
423     else
424         self->page->render(self->page, output->output_device);
425     return PY_NONE;
426 }
427
428 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
429 {
430     PageObject* self = (PageObject*)_self; 
431     
432     static char *kwlist[] = {"width", "height", NULL};
433     int width=0,height=0;
434     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
435         return NULL;
436
437     if(!width || !height) {
438         return PY_ERROR("invalid dimensions: %dx%d", width,height);
439     }
440
441     gfxdevice_t dev1,dev2;
442     gfxdevice_render_init(&dev1);
443     dev1.setparameter(&dev1, "antialise", "2");
444     gfxdevice_rescale_init(&dev2, &dev1, width, height, 0);
445     dev2.startpage(&dev2, self->page->width, self->page->height);
446     self->page->render(self->page, &dev2);
447     dev2.endpage(&dev2);
448     gfxresult_t*result = dev2.finish(&dev2);
449     gfximage_t*img = (gfximage_t*)result->get(result,"page0");
450     int l = img->width*img->height;
451     unsigned char*data = malloc(img->width*img->height*3);
452     int s,t;
453     for(t=0,s=0;t<l;s+=3,t++) {
454         data[s+0] = img->data[t].r;
455         data[s+1] = img->data[t].g;
456         data[s+2] = img->data[t].b;
457     }
458     result->destroy(result);
459     return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
460 }
461
462 static void page_dealloc(PyObject* _self) {
463     PageObject* self = (PageObject*)_self; 
464     if(self->page) {
465         self->page->destroy(self->page);
466         self->page=0;
467     }
468     if(self->parent) {
469         Py_DECREF(self->parent);
470         self->parent=0;
471     }
472     
473     PyObject_Del(self);
474 }
475 static PyObject* page_getattr(PyObject * _self, char* a)
476 {
477     PageObject*self = (PageObject*)_self;
478     
479     if(!strcmp(a, "size")) {
480         return Py_BuildValue("(ii)", self->page->width, self->page->height);
481     } if(!strcmp(a, "doc")) {
482         Py_INCREF(self->parent);
483         return self->parent;
484     } if(!strcmp(a, "nr")) {
485         return PyInt_FromLong(self->nr);
486     } else if(!strcmp(a, "width")) {
487         return PyInt_FromLong(self->page->width);
488     } else if(!strcmp(a, "height")) {
489         return PyInt_FromLong(self->page->height);
490     }
491     return Py_FindMethod(page_methods, _self, a);
492 }
493 static int page_setattr(PyObject * self, char* a, PyObject * o) {
494     return -1;
495 }
496 static int page_print(PyObject * _self, FILE *fi, int flags)
497 {
498     PageObject*self = (PageObject*)_self;
499     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
500     return 0;
501 }
502
503 //---------------------------------------------------------------------
504
505 staticforward PyObject* doc_getPage(PyObject* parent, PyObject* args, PyObject* kwargs);
506 staticforward PyObject* doc_getInfo(PyObject* parent, PyObject* args, PyObject* kwargs);
507 staticforward PyObject* doc_setParameter(PyObject* parent, PyObject* args, PyObject* kwargs);
508
509 static PyMethodDef doc_methods[] =
510 {
511     /* PDF functions */
512     {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, ""},
513     {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, ""},
514     {"setParameter", (PyCFunction)doc_setParameter, METH_KEYWORDS, ""},
515     {0,0,0,0}
516 };
517
518 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
519 {
520     DocObject* self = (DocObject*)_self;
521
522     static char *kwlist[] = {"nr", NULL};
523     int pagenr = 0;
524     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
525         return NULL;
526
527     PageObject*page = PyObject_New(PageObject, &PageClass);
528     page->page = self->doc->getpage(self->doc, pagenr);
529     page->nr = pagenr;
530     page->parent = _self;
531     Py_INCREF(page->parent);
532     if(!page->page) {
533         PyObject_Del(page);
534         return PY_ERROR("Couldn't extract page %d", pagenr);
535     }
536     return (PyObject*)page;
537 }
538
539 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
540 {
541     DocObject* self = (DocObject*)_self;
542
543     static char *kwlist[] = {"key", NULL};
544     char*key = 0;
545     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
546         return NULL;
547
548     char*s = self->doc->getinfo(self->doc, key);
549     return PyString_FromString(s);
550 }
551
552 static PyObject* doc_setParameter(PyObject* _self, PyObject* args, PyObject* kwargs)
553 {
554     DocObject* self = (DocObject*)_self;
555
556     static char *kwlist[] = {"key", "value", NULL};
557     char*key = 0, *value=0;
558     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
559         return NULL;
560
561     self->doc->set_parameter(self->doc, key, value);
562     return PY_NONE;
563 }
564
565 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
566 {
567     static char *kwlist[] = {"type", "filename", NULL};
568     char*filename;
569     char*type;
570     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename))
571         return NULL;
572
573     DocObject*self = PyObject_New(DocObject, &DriverClass);
574    
575     if(!strcmp(type,"pdf"))
576         self->doc = pdfdriver->open(pdfdriver,filename);
577     else
578         return PY_ERROR("Unknown type %s", type);
579
580     if(!self->doc) {
581         PyObject_Del(self);
582         return PY_ERROR("Couldn't open %s", filename);
583     }
584     self->filename = strdup(filename);
585     return (PyObject*)self;
586 }
587 static void doc_dealloc(PyObject* _self) {
588     DocObject* self = (DocObject*)_self;
589     if(self->doc) {
590         self->doc->destroy(self->doc);
591         self->doc=0;
592     }
593     if(self->filename) {
594         free(self->filename);self->filename=0;
595     }
596     PyObject_Del(self);
597 }
598 static PyObject* doc_getattr(PyObject * _self, char* a)
599 {
600     DocObject*self = (DocObject*)_self;
601     if(!strcmp(a, "pages")) {
602         return PyInt_FromLong(self->doc->num_pages);
603     }
604     if(!strcmp(a, "filename")) {
605         return PyString_FromString(self->filename);
606     }
607     return Py_FindMethod(doc_methods, _self, a);
608 }
609 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
610     return -1;
611 }
612 static int doc_print(PyObject * _self, FILE *fi, int flags)
613 {
614     DocObject*self = (DocObject*)_self;
615     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
616     return 0;
617 }
618
619 //---------------------------------------------------------------------
620
621 static PyTypeObject OutputClass =
622 {
623     PyObject_HEAD_INIT(NULL)
624     0,
625     tp_name: "Output",
626     tp_basicsize: sizeof(OutputObject),
627     tp_itemsize: 0,
628     tp_dealloc: output_dealloc,
629     tp_print: output_print,
630     tp_getattr: output_getattr,
631     tp_setattr: output_setattr,
632 };
633 static PyTypeObject PageClass =
634 {
635     PyObject_HEAD_INIT(NULL)
636     0,
637     tp_name: "Page",
638     tp_basicsize: sizeof(PageObject),
639     tp_itemsize: 0,
640     tp_dealloc: page_dealloc,
641     tp_print: page_print,
642     tp_getattr: page_getattr,
643     tp_setattr: page_setattr,
644 };
645 static PyTypeObject DriverClass =
646 {
647     PyObject_HEAD_INIT(NULL)
648     0,
649     tp_name: "PDF",
650     tp_basicsize: sizeof(DocObject),
651     tp_itemsize: 0,
652     tp_dealloc: doc_dealloc,
653     tp_print: doc_print,
654     tp_getattr: doc_getattr,
655     tp_setattr: doc_setattr,
656 };
657
658 //=====================================================================
659
660 static PyObject* f_setoption(PyObject* self, PyObject* args, PyObject* kwargs)
661 {
662     static char *kwlist[] = {"key", "value", NULL};
663     char*key=0,*value=0;
664     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
665         return NULL;
666     pdfdriver->set_parameter(pdfdriver,key,value);
667     return PY_NONE;
668 }
669
670 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
671 {
672     static char *kwlist[] = {"val", NULL};
673     int val;
674     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
675         return NULL;
676     setConsoleLogging(val);
677     return PY_NONE;
678 }
679
680 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
681 {
682     static char *kwlist[] = {"filename", NULL};
683     char*filename=0;
684     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
685         return NULL;
686     pdfdriver->set_parameter(pdfdriver,"font", filename);
687     return PY_NONE;
688 }
689
690 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
691 {
692     static char *kwlist[] = {"filename", NULL};
693     char*filename=0;
694     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
695         return NULL;
696     pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
697     return PY_NONE;
698 }
699
700 static PyMethodDef pdf2swf_methods[] =
701 {
702     /* sources */
703     {"open", (PyCFunction)f_open, METH_KEYWORDS, ""},
704     {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, ""},
705     {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, ""},
706     {"setoption", (PyCFunction)f_setoption, METH_KEYWORDS, ""},
707     {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, ""},
708
709     /* devices */
710     {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, ""},
711     {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, ""},
712     {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, ""},
713     {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, ""},
714
715     /* sentinel */
716     {0, 0, 0, 0}
717 };
718
719 void initgfx(void)
720 {
721     initLog(0,0,0,0,0,2);
722     OutputClass.ob_type = &PyType_Type;
723     PageClass.ob_type = &PyType_Type;
724     DriverClass.ob_type = &PyType_Type;
725  
726     pdfdriver = gfxsource_pdf_create();
727     
728     PyObject*module = Py_InitModule("gfx", pdf2swf_methods);
729 }