implemented asset resolving
[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 "../../config.h"
27 #include "../gfxtools.h"
28 #include "../devices/swf.h"
29 #include "../devices/render.h"
30 #include "../devices/ocr.h"
31 #include "../devices/rescale.h"
32 #include "../devices/text.h"
33 #ifdef USE_OPENGL
34 #include "../devices/opengl.h"
35 #endif
36 #include "../pdf/pdf.h"
37 #include "../readers/swf.h"
38 #include "../readers/image.h"
39 #include "../log.h"
40 #include "../utf8.h"
41
42 static gfxsource_t*pdfdriver = 0;
43 static gfxsource_t*swfdriver = 0;
44 static gfxsource_t*imagedriver = 0;
45
46 staticforward PyTypeObject OutputClass;
47 staticforward PyTypeObject PageClass;
48 staticforward PyTypeObject DocClass;
49
50 typedef struct {
51     PyObject_HEAD
52     gfxdevice_t*output_device;
53     PyObject*pyobj; //only for passthrough
54 } OutputObject;
55
56 typedef struct {
57     PyObject_HEAD
58     PyObject*parent;
59     gfxpage_t*page;
60     int nr;
61 } PageObject;
62
63 typedef struct {
64     PyObject_HEAD
65     gfxdocument_t*doc;
66     char*filename;
67 } DocObject;
68
69 static char* strf(char*format, ...)
70 {
71     char buf[1024];
72     int l;
73     va_list arglist;
74     va_start(arglist, format);
75     vsnprintf(buf, sizeof(buf)-1, format, arglist);
76     va_end(arglist);
77     return strdup(buf);
78 }
79 #define PY_ERROR(s,args...) (PyErr_SetString(PyExc_Exception, strf(s, ## args)),(void*)NULL)
80 #define PY_NONE Py_BuildValue("s", 0)
81
82 //---------------------------------------------------------------------
83 PyDoc_STRVAR(output_save_doc, \
84 "save(filename)\n\n"
85 "Saves the contents of an output device to a file\n"
86 "Depending on what the output device is, the contents\n"
87 "of the file may be plain text, an image, an SWF file,\n"
88 "etc.\n"
89 "For the ImageList device, several files (named\n"
90 "filename.1.png, filename.2.png etc.) might be created)\n"
91 );
92 static PyObject* output_save(PyObject* _self, PyObject* args, PyObject* kwargs)
93 {
94     OutputObject* self = (OutputObject*)_self;
95     char*filename = 0;
96     static char *kwlist[] = {"filename", NULL};
97     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
98         return NULL;
99
100     gfxresult_t*result = self->output_device->finish(self->output_device);
101     self->output_device = 0;
102     if(result->save(result, filename) < 0) {
103         return PY_ERROR("Couldn't write to %s", filename);
104     }
105     result->destroy(result);
106     return PY_NONE;
107 }
108
109 PyDoc_STRVAR(output_startpage_doc, \
110 "startpage(width, height)\n\n"
111 "Starts a new page/frame in the output device.\n"
112 "The usual way to render documents is to start a new page in the\n"
113 "device for each page in the document:\n"
114 "\n"
115 "for pagenr in range(1,doc.pages+1):\n"
116 "    page = doc.getPage(pagenr)\n"
117 "    output.startpage(page.width, page.height)\n"
118 "    page.render(output)\n"
119 "    output.endpage()\n"
120 "\n"
121 "It is, however, also possible to render more than one document page\n"
122 "to a single output page. E.g. for side-by-side or book views.\n"
123 );
124 static PyObject* output_startpage(PyObject* _self, PyObject* args, PyObject* kwargs)
125 {
126     OutputObject* self = (OutputObject*)_self;
127     int width=0, height=0;
128     if (!PyArg_ParseTuple(args, "ii", &width, &height))
129         return NULL;
130     self->output_device->startpage(self->output_device, width, height);
131     return PY_NONE;
132 }
133
134 /* as the definition of the python image type comes from another module (not
135    included here, reproduce the necessary structure and extract the image
136    without using the type definition */
137 typedef struct {
138     PyObject_HEAD
139     gfximage_t*image;
140     PyObject* strrepr;
141 } ImageObject;
142 static gfximage_t*toImage(PyObject*_bitmap)
143 {
144     if(!_bitmap || !_bitmap->ob_type->tp_name || strcmp(_bitmap->ob_type->tp_name, "Image")) {
145         PY_ERROR("Second argument to fillbitmap must be an image");
146         return 0;
147     }
148     ImageObject*bitmap = (ImageObject*)_bitmap;
149     return bitmap->image;
150 }
151
152 static gfxline_t*toLine(PyObject*_line)
153 {
154     int t;
155     int num = PyList_Size(_line);
156     gfxline_t first;
157     first.next = 0;
158     gfxline_t*last=&first;
159     for(t=0;t<num;t++) {
160         PyObject*p= PySequence_GetItem(_line, t);
161         if(!PyTuple_Check(p)) {
162             return PY_ERROR("each point must be a tuple");
163         }
164         PyObject*_type = PyTuple_GetItem(p, 0);
165         if(!PyString_Check(_type))
166             return PY_ERROR("point tuples must start with a string");
167         char*type = PyString_AsString(_type);
168         int s;
169         int size = PyTuple_Size(p);
170         for(s=1;s<size;s++) {
171             if(!PyFloat_Check(PyTuple_GetItem(p,s))) {
172                 return PY_ERROR("coordinates must be floats");
173             }
174         }
175         gfxline_t*l = (gfxline_t*)malloc(sizeof(gfxline_t));
176         memset(l, 0, sizeof(gfxline_t));
177         last->next = l;
178         last = l;
179         if(type[0]=='m') {
180             l->type = gfx_moveTo;
181             if(size!=3)
182                 return PY_ERROR("need 2 values for move");
183             l->x = PyFloat_AsDouble(PyTuple_GetItem(p, 1));
184             l->y = PyFloat_AsDouble(PyTuple_GetItem(p, 2));
185         } else if(type[0]=='l') {
186             l->type = gfx_lineTo;
187             if(size!=3)
188                 return PY_ERROR("need 2 values for line");
189             l->x = PyFloat_AsDouble(PyTuple_GetItem(p, 1));
190             l->y = PyFloat_AsDouble(PyTuple_GetItem(p, 2));
191         } else if(type[0]=='s') {
192             l->type = gfx_splineTo;
193             if(size!=5)
194                 return PY_ERROR("need 4 values for spline");
195             l->x = PyFloat_AsDouble(PyTuple_GetItem(p, 1));
196             l->y = PyFloat_AsDouble(PyTuple_GetItem(p, 2));
197             l->sx = PyFloat_AsDouble(PyTuple_GetItem(p, 3));
198             l->sy = PyFloat_AsDouble(PyTuple_GetItem(p, 4));
199         } else {
200             return PY_ERROR("Unknown line code '%s'", type);
201         }
202     }
203     return first.next;
204 }
205
206 PyDoc_STRVAR(output_fillbitmap_doc, \
207 "fillbitmap()\n\n"
208 "fill a polygon with a bitmap pattern\n"
209 );
210 static PyObject* output_fillbitmap(PyObject* _self, PyObject* args, PyObject* kwargs)
211 {
212     OutputObject* self = (OutputObject*)_self;
213     PyObject*_line=0;
214     PyObject*_bitmap=0;
215     static char *kwlist[] = {"line", "bitmap", NULL};
216
217     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", kwlist, &PyList_Type, &_line, &_bitmap))
218         return NULL;
219
220     gfximage_t*image = toImage(_bitmap);
221     if(!image)
222         return PY_ERROR("invalid image");
223
224     gfxline_t*line = toLine(_line);
225     if(!line) 
226         return 0;
227
228     /* TODO */
229     gfxmatrix_t m;
230     memset(&m, 0, sizeof(gfxmatrix_t));
231     m.m00 = m.m11 = 1.0;
232
233     self->output_device->fillbitmap(self->output_device, line, image, &m, 0);
234     gfxline_free(line);
235     return PY_NONE;
236 }
237
238 PyDoc_STRVAR(output_fill_doc, \
239 "fill()\n\n"
240 "fill a polygon with a color\n"
241 );
242 static PyObject* output_fill(PyObject* _self, PyObject* args, PyObject* kwargs)
243 {
244     OutputObject* self = (OutputObject*)_self;
245     PyObject*_line=0;
246     PyObject*_bitmap=0;
247     static char *kwlist[] = {"line", "color", NULL};
248
249     PyObject* color=0;
250
251     int a=255,r=0,g=0,b=0;
252     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", kwlist, &PyList_Type, &_line, &color))
253         return NULL;
254
255     if(!PyArg_ParseTuple(color, "iiii:color",  &a, &r, &g, &b)) {
256         return NULL;
257     }
258
259     gfxcolor_t c;
260     c.r = r; c.g = g; c.b = b; c.a = a;
261
262     gfxline_t*line = toLine(_line);
263     if(!line) 
264         return 0;
265
266     /* TODO */
267     gfxmatrix_t m;
268     memset(&m, 0, sizeof(gfxmatrix_t));
269     m.m00 = m.m11 = 1.0;
270
271     self->output_device->fill(self->output_device, line, &c);
272     gfxline_free(line);
273     return PY_NONE;
274 }
275
276 PyDoc_STRVAR(output_stroke_doc, \
277 "stroke()\n\n"
278 "stroke a polygon with a color\n"
279 );
280 static PyObject* output_stroke(PyObject* _self, PyObject* args, PyObject* kwargs)
281 {
282     OutputObject* self = (OutputObject*)_self;
283     PyObject*_line=0;
284     PyObject*_bitmap=0;
285     static char *kwlist[] = {"line", "width", "color", NULL};
286
287     PyObject* color=0;
288
289     int a=255,r=0,g=0,b=0;
290     float width = 1.0;
291     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!fO", kwlist, &PyList_Type, &_line, &width, &color))
292         return NULL;
293
294     if(!PyArg_ParseTuple(color, "iiii:color",  &a, &r, &g, &b)) {
295         return NULL;
296     }
297
298     gfxcolor_t c;
299     c.r = r; c.g = g; c.b = b; c.a = a;
300
301     gfxline_t*line = toLine(_line);
302     if(!line) 
303         return 0;
304
305     self->output_device->stroke(self->output_device, line, width, &c, 
306             /*TODO*/ gfx_capRound, gfx_joinRound, 0.0);
307     gfxline_free(line);
308     return PY_NONE;
309 }
310
311 PyDoc_STRVAR(output_endpage_doc, \
312 "endpage()\n\n"
313 "Ends a page in the output device. This function should be called\n"
314 "once for every startpage()\n"
315 );
316 static PyObject* output_endpage(PyObject* _self, PyObject* args, PyObject* kwargs)
317 {
318     OutputObject* self = (OutputObject*)_self;
319     if (!PyArg_ParseTuple(args, ""))
320         return NULL;
321     self->output_device->endpage(self->output_device);
322     return PY_NONE;
323 }
324 PyDoc_STRVAR(output_setparameter_doc, \
325 "setparameter(key, value)\n\n"
326 "Set a output-device dependent parameter"
327 );
328 static PyObject* output_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
329 {
330     OutputObject* self = (OutputObject*)_self;
331     static char *kwlist[] = {"key", "value", NULL};
332     char*key=0,*value=0;
333     if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
334         return NULL;
335     self->output_device->setparameter(self->output_device, key, value);
336     return PY_NONE;
337 }
338 PyDoc_STRVAR(f_createSWF_doc, \
339 "SWF()\n\n"
340 "Creates a device which renders documents to SWF (Flash) files.\n"
341 "Depending on the way the document parser behaves (see the poly2bitmap\n"
342 "and bitmap parameters), the resulting SWF might use vector operations\n"
343 "and Flash Texts to display the document, or just a single bitmap.\n"
344 );
345 static PyObject* f_createSWF(PyObject* parent, PyObject* args, PyObject* kwargs)
346 {
347     static char *kwlist[] = {NULL};
348     if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
349         return NULL;
350     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
351     
352     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
353     gfxdevice_swf_init(self->output_device);
354     return (PyObject*)self;
355 }
356
357 PyDoc_STRVAR(f_createOCR_doc, \
358 "OCR()\n\n"
359 "Creates a device which processes documents using OCR (optical\n"
360 "character recognition).\n"
361 "This is handy for e.g. extracting fulltext from PDF documents\n"
362 "which have broken fonts, and where hence the \"PlainText\"\n"
363 "device doesn't work.\n"
364 );
365 static PyObject* f_createOCR(PyObject* parent, PyObject* args, PyObject* kwargs)
366 {
367     static char *kwlist[] = {NULL};
368     if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
369         return NULL;
370     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
371     
372     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
373     gfxdevice_ocr_init(self->output_device);
374     return (PyObject*)self;
375 }
376
377
378 PyDoc_STRVAR(f_createImageList_doc, \
379 "ImageList()\n\n"
380 "Creates a device which renders documents to bitmaps.\n"
381 "Each page that is rendered will create new bitmap.\n"
382 "Using save(), you can save the images to a number\n"
383 "of files\n"
384 );
385 static PyObject* f_createImageList(PyObject* parent, PyObject* args, PyObject* kwargs)
386 {
387     static char *kwlist[] = {NULL};
388     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
389         return NULL;
390     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
391     
392     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
393     gfxdevice_render_init(self->output_device);
394     return (PyObject*)self;
395 }
396
397 PyDoc_STRVAR(f_createPlainText_doc, \
398 "PlainText()\n\n"
399 "Creates a device which can be used to extract text from documents,\n"
400 "by passing it as parameter to page.render().\n"
401 "The extracted text can be saved by plaintext.save(filename).\n"
402 );
403 static PyObject* f_createPlainText(PyObject* parent, PyObject* args, PyObject* kwargs)
404 {
405     static char *kwlist[] = {NULL};
406     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
407         return NULL;
408     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
409     
410     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
411     gfxdevice_text_init(self->output_device);
412     return (PyObject*)self;
413 }
414
415 #ifdef USE_OPENGL
416 PyDoc_STRVAR(f_createOpenGL_doc, \
417 "OpenGL()\n\n"
418 "Creates a device which renders everything to OpenGL.\n"
419 "Can be used for desktop display and debugging.\n"
420 "This device is not available on all systems.\n"
421 );
422 static PyObject* f_createOpenGL(PyObject* parent, PyObject* args, PyObject* kwargs)
423 {
424     static char *kwlist[] = {NULL};
425     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
426         return NULL;
427     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
428     
429     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
430     gfxdevice_opengl_init(self->output_device);
431     return (PyObject*)self;
432 }
433 #endif
434
435 static char callback_python(char*function, gfxdevice_t*dev, const char*format, ...)
436 {
437     OutputObject*self = (OutputObject*)dev->internal;
438
439     if(!PyObject_HasAttrString(self->pyobj, function))
440         return 0;
441
442     va_list ap;
443     va_start(ap, format);
444
445     PyObject*tuple = PyTuple_New(strlen(format));
446     int pos = 0;
447     while(format[pos]) {
448         char p = format[pos];
449         if(p=='s') {
450             char*s = va_arg(ap, char*);
451             PyTuple_SetItem(tuple, pos, PyString_FromString(s));
452         } else if(p=='i') {
453             int i = va_arg(ap, int);
454             PyTuple_SetItem(tuple, pos, PyInt_FromLong(i));
455         } else if(p=='d') {
456             int i = va_arg(ap, double);
457             PyTuple_SetItem(tuple, pos, PyFloat_FromDouble(i));
458         } else if(p=='c') {
459             void* ptr = va_arg(ap, void*);
460             gfxcolor_t*col = (gfxcolor_t*)ptr;
461             PyObject*colobj = PyTuple_New(4);
462             PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->a));
463             PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->r));
464             PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->g));
465             PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->b));
466             PyTuple_SetItem(tuple, pos, colobj);
467         } else if(p=='l') {
468             void* ptr = va_arg(ap, void*);
469             gfxline_t*line = (gfxline_t*)ptr;
470             gfxline_t*l;
471             int len = 0, i = 0;
472             l = line;
473             while(l) {l=l->next;len++;}
474             PyObject*list = PyList_New(len);
475             l = line;
476             while(l) {
477                 PyObject*point=0;
478                 if(l->type == gfx_moveTo) {
479                     point = PyTuple_New(3);
480                     PyTuple_SetItem(point, 0, PyString_FromString("m"));
481                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
482                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
483                 } else if(l->type == gfx_lineTo) {
484                     point = PyTuple_New(3);
485                     PyTuple_SetItem(point, 0, PyString_FromString("l"));
486                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
487                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
488                 } else if(l->type == gfx_splineTo) {
489                     point = PyTuple_New(5);
490                     PyTuple_SetItem(point, 0, PyString_FromString("s"));
491                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
492                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
493                     PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sx));
494                     PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
495                 } else {
496                     point = PY_NONE;
497                 }
498                 PyList_SetItem(list, i, point);
499                 l = l->next;
500                 i++;
501             }
502             PyTuple_SetItem(tuple, pos, list);
503         } else {
504             PyTuple_SetItem(tuple, pos, PY_NONE);
505         }
506         pos++;
507     }
508     va_end(ap);
509     PyObject*f = PyObject_GetAttrString(self->pyobj, function);
510     if(!f)
511         return 0;
512     PyErr_Clear();
513     PyObject* result = PyObject_CallObject(f, tuple);
514
515     if(!result) { 
516         PyErr_Print();
517         PyErr_Clear();
518         return 1;
519     } else {
520         Py_DECREF(result);
521         return 1;
522     }
523 }
524     
525 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
526 {
527     callback_python("setparameter", dev, "ss", key, value);
528     return 1;
529 }
530 static void my_startpage(gfxdevice_t*dev, int width, int height)
531 {
532     callback_python("startpage", dev, "ii", width, height);
533 }
534 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
535 {
536     callback_python("startclip", dev, "l", line);
537 }
538 static void my_endclip(gfxdevice_t*dev)
539 {
540     callback_python("endclip", dev, "");
541 }
542 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)
543 {
544     char*cap = 0;
545     char*joint = 0;
546     if(cap_style == gfx_capButt)
547         cap = "butt";
548     else if(cap_style == gfx_capRound)
549         cap = "round";
550     else if(cap_style == gfx_capSquare)
551         cap = "square";
552     if(joint_style == gfx_joinMiter)
553         joint = "miter";
554     else if(joint_style == gfx_joinRound)
555         joint = "round";
556     else if(joint_style == gfx_joinBevel)
557         joint = "bevel";
558     callback_python("stroke", dev, "ldcssi", line, width, color, cap, joint, miterLimit);
559 }
560 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
561 {
562     callback_python("fill", dev, "lc", line, color);
563 }
564 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
565 {
566     callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
567 }
568 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
569 {
570     callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
571 }
572 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
573 {
574     callback_python("addfont", dev, "f", font);
575 }
576 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
577 {
578     if(!callback_python("drawchar", dev, "ficm", font, glyphnr, color, matrix))
579     {
580         if(!font)
581             return;
582         gfxglyph_t*glyph = &font->glyphs[glyphnr];
583         gfxline_t*line2 = gfxline_clone(glyph->line);
584         gfxline_transform(line2, matrix);
585         my_fill(dev, line2, color);
586         gfxline_free(line2);
587         return;
588     }
589 }
590 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
591 {
592     callback_python("drawlink", dev, "ls", line, action);
593 }
594 static void my_endpage(gfxdevice_t*dev)
595 {
596     callback_python("drawlink", dev, "");
597 }
598 static gfxresult_t* my_finish(gfxdevice_t*dev)
599 {
600     callback_python("finish", dev, "");
601     return 0;
602 }
603
604
605 PyDoc_STRVAR(f_createPassThrough_doc, \
606 "PassThrough(device)\n\n"
607 "Creates a PassThrough device, which can be used as parameter in calls\n"
608 "to page.render().\n"
609 "device needs to be a class implementing at least the following functions:\n\n"
610 "setparameter(key,value)\n"
611 "startclip(outline)\n"
612 "endclip()\n"
613 "stroke(outline, width, color, capstyle, jointstyle, miterLimit)\n"
614 "fill(outline, color)\n"
615 "fillbitmap(outline, image, matrix, colortransform)\n"
616 "fillgradient(outline, gradient, gradienttype, matrix)\n"
617 "addfont(font)\n"
618 "drawchar(font, glyph, color, matrix)\n"
619 "drawlink(outline, url)\n"
620 "If any of these functions are not defined, a error message will be printed,\n"
621 "however the rendering process will *not* be aborted.\n"
622 );
623 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
624 {
625     static char *kwlist[] = {"device", NULL};
626     PyObject*obj;
627     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
628         return NULL;
629     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
630    
631     self->pyobj = obj;
632     Py_INCREF(obj);
633     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
634     memset(self->output_device, 0, sizeof(gfxdevice_t));
635     self->output_device->name = strdup("passthrough");
636
637     self->output_device->setparameter = my_setparameter;
638     self->output_device->startpage = my_startpage;
639     self->output_device->startclip = my_startclip;
640     self->output_device->addfont = my_addfont;
641     self->output_device->endclip = my_endclip;
642     self->output_device->stroke = my_stroke;
643     self->output_device->fill = my_fill;
644     self->output_device->fillbitmap = my_fillbitmap;
645     self->output_device->fillgradient = my_fillgradient;
646     self->output_device->drawchar = my_drawchar;
647     self->output_device->drawlink = my_drawlink;
648     self->output_device->endpage = my_endpage;
649     self->output_device->finish = my_finish;
650     self->output_device->internal = self;
651
652     return (PyObject*)self;
653 }
654
655 static PyMethodDef output_methods[] =
656 {
657     /* Output functions */
658     {"save", (PyCFunction)output_save, METH_KEYWORDS, output_save_doc},
659     {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, output_startpage_doc},
660     {"fill", (PyCFunction)output_fill, METH_KEYWORDS, output_fill_doc},
661     {"fillbitmap", (PyCFunction)output_fillbitmap, METH_KEYWORDS, output_fillbitmap_doc},
662     {"stroke", (PyCFunction)output_stroke, METH_KEYWORDS, output_stroke_doc},
663     {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, output_endpage_doc},
664     {"setparameter", (PyCFunction)output_setparameter, METH_KEYWORDS, output_setparameter_doc},
665     {0,0,0,0}
666 };
667
668 static void output_dealloc(PyObject* _self) {
669     OutputObject* self = (OutputObject*)_self;
670
671     if(self->output_device) {
672         gfxresult_t*result = self->output_device->finish(self->output_device);
673         if(result) {
674             result->destroy(result);result=0;
675         }
676         self->output_device = 0;
677     }
678     
679     PyObject_Del(self);
680 }
681 static PyObject* output_getattr(PyObject * _self, char* a)
682 {
683     OutputObject*self = (OutputObject*)_self;
684    
685 /*    if(!strcmp(a, "x1")) {
686         return PyInt_FromLong(self->output_device->x1);
687     } else if(!strcmp(a, "y1")) {
688         return PyInt_FromLong(self->output_device->y1);
689     } else if(!strcmp(a, "x2")) {
690         return PyInt_FromLong(self->output_device->x2);
691     } else if(!strcmp(a, "y2")) {
692         return PyInt_FromLong(self->output_device->y2);
693     }*/
694     
695     return Py_FindMethod(output_methods, _self, a);
696 }
697 static int output_setattr(PyObject * _self, char* a, PyObject * o) 
698 {
699     OutputObject*self = (OutputObject*)_self;
700     if(!PyString_Check(o))
701         return -1;
702     char*value = PyString_AsString(o);
703     self->output_device->setparameter(self->output_device, a, value);
704     return -1;
705 }
706 static int output_print(PyObject * _self, FILE *fi, int flags)
707 {
708     OutputObject*self = (OutputObject*)_self;
709     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
710     return 0;
711 }
712
713 //---------------------------------------------------------------------
714 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
715 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
716
717 PyDoc_STRVAR(page_render_doc, \
718 "render(output, move=(0,0), clip=None)\n\n"
719 "Renders a page to the rendering backend specified by the output\n"
720 "parameter. Rendering consists of calling a number of functions on the\n"
721 "output device, see the description of the \"PassThrough\" device.\n"
722 "The page may be shifted to a given position using the move parameter,\n"
723 "and may also be clipped to a specific size using the clip parameter.\n"
724 "The clipping operation is applied after the move operation.\n"
725 );
726 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
727 {
728     PageObject* self = (PageObject*)_self; 
729     
730     static char *kwlist[] = {"dev", "move", "clip", NULL};
731     OutputObject*output = 0;
732     PyObject*move=0;
733     PyObject*clip=0;
734     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
735                 &move,&clip
736                 ))
737         return NULL;
738
739     int x=0,y=0;
740     int cx1=0,cy1=0,cx2=0,cy2=0;
741
742     if(move) {
743         if (!PyArg_ParseTuple(move, "ii", &x,&y))
744             return NULL;
745     }
746     if(clip) {
747         if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
748             return NULL;
749     }
750
751     if(x|y|cx1|cx2|cy1|cy2)
752         self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
753     else
754         self->page->render(self->page, output->output_device);
755     return PY_NONE;
756 }
757
758 PyDoc_STRVAR(page_asImage_doc, \
759 "asImage(width, height)\n\n"
760 "Creates a bitmap from a page. The bitmap will be returned as a string\n"
761 "containing RGB triplets. The bitmap will be rescaled to the specified width and\n"
762 "height. The aspect ratio of width and height doesn't need to be the same\n"
763 "as the page.\n"
764 );
765 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
766 {
767     PageObject* self = (PageObject*)_self; 
768     
769     static char *kwlist[] = {"width", "height", NULL};
770     int width=0,height=0;
771     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
772         return NULL;
773
774     if(!width || !height) {
775         return PY_ERROR("invalid dimensions: %dx%d", width,height);
776     }
777
778     gfxdevice_t dev1,dev2;
779     gfxdevice_render_init(&dev1);
780     dev1.setparameter(&dev1, "antialise", "2");
781     gfxdevice_rescale_init(&dev2, &dev1, width, height, 0);
782     dev2.startpage(&dev2, self->page->width, self->page->height);
783     self->page->render(self->page, &dev2);
784     dev2.endpage(&dev2);
785     gfxresult_t*result = dev2.finish(&dev2);
786     gfximage_t*img = (gfximage_t*)result->get(result,"page0");
787     int l = img->width*img->height;
788     unsigned char*data = (unsigned char*)malloc(img->width*img->height*3);
789     int s,t;
790     for(t=0,s=0;t<l;s+=3,t++) {
791         data[s+0] = img->data[t].r;
792         data[s+1] = img->data[t].g;
793         data[s+2] = img->data[t].b;
794     }
795     result->destroy(result);
796     return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
797 }
798
799 static PyMethodDef page_methods[] =
800 {
801     /* Page functions */
802     {"render", (PyCFunction)page_render, METH_KEYWORDS, page_render_doc},
803     {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, page_asImage_doc},
804     {0,0,0,0}
805 };
806 static void page_dealloc(PyObject* _self) {
807     PageObject* self = (PageObject*)_self; 
808     if(self->page) {
809         self->page->destroy(self->page);
810         self->page=0;
811     }
812     if(self->parent) {
813         Py_DECREF(self->parent);
814         self->parent=0;
815     }
816     
817     PyObject_Del(self);
818 }
819
820 static PyObject* page_getattr(PyObject * _self, char* a)
821 {
822     PageObject*self = (PageObject*)_self;
823     
824     if(!strcmp(a, "size")) {
825         return Py_BuildValue("(ii)", self->page->width, self->page->height);
826     } if(!strcmp(a, "doc")) {
827         Py_INCREF(self->parent);
828         return self->parent;
829     } if(!strcmp(a, "nr")) {
830         return PyInt_FromLong(self->nr);
831     } else if(!strcmp(a, "width")) {
832         return PyInt_FromLong(self->page->width);
833     } else if(!strcmp(a, "height")) {
834         return PyInt_FromLong(self->page->height);
835     }
836     return Py_FindMethod(page_methods, _self, a);
837 }
838
839 static int page_setattr(PyObject * self, char* a, PyObject * o) {
840     return -1;
841 }
842 static int page_print(PyObject * _self, FILE *fi, int flags)
843 {
844     PageObject*self = (PageObject*)_self;
845     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
846     return 0;
847 }
848
849 //---------------------------------------------------------------------
850
851 PyDoc_STRVAR(doc_getPage_doc,
852 "getPage(nr)\n\n"
853 "Get one page from a document file. The nr parameter specifies\n"
854 "which page to retrieve. Counting starts at 1, so the first page\n"
855 "can be retrieved by\n"
856 "    page = doc.getPage(1)\n"
857 ".\n"
858 "You can find out how many pages a document contains by querying\n"
859 "its pages field (doc.pages)\n"
860 );
861 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
862 {
863     DocObject* self = (DocObject*)_self;
864
865     static char *kwlist[] = {"nr", NULL};
866     int pagenr = 0;
867     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
868         return NULL;
869
870     PageObject*page = PyObject_New(PageObject, &PageClass);
871     page->page = self->doc->getpage(self->doc, pagenr);
872     page->nr = pagenr;
873     page->parent = _self;
874     Py_INCREF(page->parent);
875     if(!page->page) {
876         PyObject_Del(page);
877         return PY_ERROR("Couldn't extract page %d", pagenr);
878     }
879     return (PyObject*)page;
880 }
881
882 PyDoc_STRVAR(doc_getInfo_doc,
883 "getInfo(key)\n\n"
884 "Retrieve some information about a document. For PDF files, key\n"
885 "can have the following values:\n\n"
886 "\"title\", \"subject\", \"keywords\", \"author\", \"creator\", \"producer\",\n"
887 "\"creationdate\", \"moddate\", \"linearized\", \"tagged\", \"encrypted\",\n"
888 "\"oktoprint\", \"oktocopy\", \"oktochange\", \"oktoaddnotes\", \"version\".\n\n"
889 "If the \"oktocopy\" digital rights management flag is set to \"no\", then the\n"
890 "pdf parser won't allow you to access the PDF file. Trying to extract pages\n"
891 "from it will raise an exception.\n"
892 );
893 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
894 {
895     DocObject* self = (DocObject*)_self;
896
897     static char *kwlist[] = {"key", NULL};
898     char*key = 0;
899     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
900         return NULL;
901
902     char*s = self->doc->getinfo(self->doc, key);
903     return PyString_FromString(s);
904 }
905
906 PyDoc_STRVAR(doc_setparameter_doc,
907 "setparameter(key, value)\n\n"
908 "Pass a parameter or setting to the document parser. Unlike\n"
909 "the module level setparameter() function, the parameters set\n"
910 "using setparameter will only be valid for the object itself\n"
911 "during its lifetime.\n"
912 );
913 static PyObject* doc_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
914 {
915     DocObject* self = (DocObject*)_self;
916
917     static char *kwlist[] = {"key", "value", NULL};
918     char*key = 0, *value=0;
919     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
920         return NULL;
921
922     self->doc->setparameter(self->doc, key, value);
923     return PY_NONE;
924 }
925
926 PyDoc_STRVAR(f_open_doc,
927 "open(type, filename) -> object\n\n"
928 "Open a PDF, SWF or image file. The type argument should be \"pdf\",\n"
929 "\"swf\" or \"image\" accordingly. It returns a doc object which can be\n"
930 "used to process the file contents.\n"
931 "E.g.\n"
932 "    doc = open(\"pdf\", \"document.pdf\")\n"
933 "    doc = open(\"swf\", \"flashfile.swf\")\n"
934 "    doc = open(\"image\", \"image.png\")\n"
935 "If the file could not be loaded, or is a encrypted PDF file without\n"
936 "a proper password specified, an exception is being raised.\n"
937 "If the filename argument contains a '|' char, everything behind\n"
938 "the '|' is treated as password used for opening the file.\n"
939 "E.g.\n"
940 "    doc = open(\"pdf\", \"document.pdf|mysecretpassword\")\n"
941 ".\n"
942 "Notice that for image files, the only supported file formats right now\n"
943 "are jpeg and png.\n"
944 );
945 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
946 {
947     static char *kwlist[] = {"type", "filename", NULL};
948     char*filename=0;
949     char*type=0;
950     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename)) {
951         static char *kwlist2[] = {"filename", NULL};
952         type = 0;
953         PyErr_Clear();
954         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist2, &filename))
955             return NULL;
956     }
957
958     DocObject*self = PyObject_New(DocObject, &DocClass);
959
960     if(!type) { //autodetect
961         type = "pdf"; //default
962         int l = strlen(filename);
963         if(l>4) {
964             if(filename[l-4]=='.') {
965                 if(strchr("pP", filename[l-3]) && strchr("dD", filename[l-2]) && strchr("fF", filename[l-1]))
966                     type = "pdf";
967                 if(strchr("jJ", filename[l-3]) && strchr("pP", filename[l-2]) && strchr("gG", filename[l-1]))
968                     type = "image";
969                 if(strchr("pP", filename[l-3]) && strchr("nN", filename[l-2]) && strchr("gG", filename[l-1]))
970                     type = "image";
971                 if(strchr("sS", filename[l-3]) && strchr("wW", filename[l-2]) && strchr("fF", filename[l-1]))
972                     type = "swf";
973             } else if(filename[l-5]=='.') {
974                 type = "image";
975             }
976         }
977     }
978    
979     if(!strcmp(type,"pdf"))
980         self->doc = pdfdriver->open(pdfdriver,filename);
981     else if(!strcmp(type, "image") || !strcmp(type, "img"))  
982         self->doc = imagedriver->open(imagedriver, filename);
983     else if(!strcmp(type, "swf") || !strcmp(type, "SWF"))
984         self->doc = swfdriver->open(imagedriver, filename);
985     else
986         return PY_ERROR("Unknown type %s", type);
987
988     if(!self->doc) {
989         PyObject_Del(self);
990         return PY_ERROR("Couldn't open %s", filename);
991     }
992     self->filename = strdup(filename);
993     return (PyObject*)self;
994 }
995
996 static PyMethodDef doc_methods[] =
997 {
998     /* PDF functions */
999     {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, doc_getPage_doc},
1000     {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, doc_getInfo_doc},
1001     {"setparameter", (PyCFunction)doc_setparameter, METH_KEYWORDS, doc_setparameter_doc},
1002     {0,0,0,0}
1003 };
1004
1005 static void doc_dealloc(PyObject* _self) {
1006     DocObject* self = (DocObject*)_self;
1007     if(self->doc) {
1008         self->doc->destroy(self->doc);
1009         self->doc=0;
1010     }
1011     if(self->filename) {
1012         free(self->filename);self->filename=0;
1013     }
1014     PyObject_Del(self);
1015 }
1016 static PyObject* doc_getattr(PyObject * _self, char* a)
1017 {
1018     DocObject*self = (DocObject*)_self;
1019     if(!strcmp(a, "pages")) {
1020         return PyInt_FromLong(self->doc->num_pages);
1021     }
1022     if(!strcmp(a, "filename")) {
1023         return PyString_FromString(self->filename);
1024     }
1025     return Py_FindMethod(doc_methods, _self, a);
1026 }
1027 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
1028     return -1;
1029 }
1030 static int doc_print(PyObject * _self, FILE *fi, int flags)
1031 {
1032     DocObject*self = (DocObject*)_self;
1033     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
1034     return 0;
1035 }
1036
1037 //---------------------------------------------------------------------
1038
1039 PyDoc_STRVAR(output_doc,
1040 "An Output object can be used as parameter to the render()\n"
1041 "call of a page. It's not possible to create this type of\n"
1042 "object directly (i.e., from a class), however you can\n"
1043 "use a PassThrough() device to pass things over to Python.\n"
1044 "Examples for classes implementing the Output class are: \n"
1045 "ImageList, SWF, PlainText and PassThrough.\n"
1046 );
1047 static PyTypeObject OutputClass =
1048 {
1049     PyObject_HEAD_INIT(NULL)
1050     0,
1051     tp_name: "gfx.Output",
1052     tp_basicsize: sizeof(OutputObject),
1053     tp_itemsize: 0,
1054     tp_dealloc: output_dealloc,
1055     tp_print: output_print,
1056     tp_getattr: output_getattr,
1057     tp_setattr: output_setattr,
1058     tp_doc: output_doc,
1059     tp_methods: output_methods
1060 };
1061 PyDoc_STRVAR(page_doc,
1062 "A Page object contains a single page of a document.\n"
1063 "page.width and page.height (or page.size) contain the\n"
1064 "page dimensions. page.nr is the number of the page, and\n"
1065 "page.doc is the parent document.\n"
1066 );
1067 static PyTypeObject PageClass =
1068 {
1069     PyObject_HEAD_INIT(NULL)
1070     0,
1071     tp_name: "gfx.Page",
1072     tp_basicsize: sizeof(PageObject),
1073     tp_itemsize: 0,
1074     tp_dealloc: page_dealloc,
1075     tp_print: page_print,
1076     tp_getattr: page_getattr,
1077     tp_setattr: page_setattr,
1078     tp_doc: page_doc,
1079     tp_methods: page_methods
1080 };
1081 PyDoc_STRVAR(doc_doc,
1082 "A Doc object is used for storing a document (like a PDF).\n"
1083 "doc.pages contains the number of pages in the document,\n"
1084 "and doc.filename the name of the file the document was\n"
1085 "created (loaded) from. If the document was created from\n"
1086 "an image file, the number of pages is always 1\n"
1087 );
1088 static PyTypeObject DocClass =
1089 {
1090     PyObject_HEAD_INIT(NULL)
1091     0,
1092     tp_name: "gfx.Doc",
1093     tp_basicsize: sizeof(DocObject),
1094     tp_itemsize: 0,
1095     tp_dealloc: doc_dealloc,
1096     tp_print: doc_print,
1097     tp_getattr: doc_getattr,
1098     tp_setattr: doc_setattr,
1099     tp_doc: doc_doc,
1100     tp_methods: doc_methods,
1101 };
1102
1103 //=====================================================================
1104
1105 PyDoc_STRVAR(f_setparameter_doc, \
1106 "setparameter(key,value)\n\n"
1107 "Set a parameter in the gfx module (which might affect the PDF\n"
1108 "parser or any of the rendering backends). This is a parameter\n"
1109 "which would usually be passed with the \"-s\" option to pdf2swf.\n"
1110 "For a list of all parameters, see the output of\n"
1111 "    pdf2swf -s help\n"
1112 "and\n"
1113 "    pdf2swf somefile.pdf -s help\n"
1114 ".\n"
1115 );
1116 static PyObject* f_setparameter(PyObject* self, PyObject* args, PyObject* kwargs)
1117 {
1118     static char *kwlist[] = {"key", "value", NULL};
1119     char*key=0,*value=0;
1120     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
1121         return NULL;
1122     pdfdriver->setparameter(pdfdriver,key,value);
1123     return PY_NONE;
1124 }
1125
1126 PyDoc_STRVAR(f_verbose_doc, \
1127 "verbose(level)\n\n"
1128 "Set the logging verbosity of the gfx module. Log levels are:\n"
1129 "level=-1          Log nothing\n"
1130 "level=0 (fatal)   Log only fatal errors\n"
1131 "level=1 (error)   Log only fatal errors and errors\n"
1132 "level=2 (warn)    Log all errors and warnings\n"
1133 "level=3 (notice)  Log also some rudimentary data about the parsing/conversion\n"
1134 "level=4 (verbose) Log some additional parsing information\n"
1135 "level=5 (debug)   Log debug statements\n"
1136 "level=6 (trace)   Log extended debug statements\n"
1137 "All logging messages are written to stdout.\n"
1138 );
1139 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
1140 {
1141     static char *kwlist[] = {"val", NULL};
1142     int val;
1143     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
1144         return NULL;
1145     setConsoleLogging(val);
1146     return PY_NONE;
1147 }
1148
1149 PyDoc_STRVAR(f_addfont_doc, \
1150 "addfont(filename)\n\n"
1151 "Passes an additional font file to the PDF parser. If a PDF contains\n"
1152 "external fonts (i.e. fonts which are not contained in the PDF itself)\n"
1153 "then the files added by addfont() will be searched.\n"
1154 );
1155
1156 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
1157 {
1158     static char *kwlist[] = {"filename", NULL};
1159     char*filename=0;
1160     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
1161         return NULL;
1162     pdfdriver->setparameter(pdfdriver,"font", filename);
1163     return PY_NONE;
1164 }
1165
1166 PyDoc_STRVAR(f_addfontdir_doc, \
1167 "addfontdir(dirname)\n\n"
1168 "Passes a complete directory containing fonts to the PDF parser. Any\n"
1169 "font file within this directory might be used to resolve external fonts\n"
1170 "in PDF files\n"
1171 );
1172 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
1173 {
1174     static char *kwlist[] = {"filename", NULL};
1175     char*filename=0;
1176     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
1177         return NULL;
1178     pdfdriver->setparameter(pdfdriver,"fontdir", filename);
1179     return PY_NONE;
1180 }
1181
1182 static PyMethodDef pdf2swf_methods[] =
1183 {
1184     /* sources */
1185     {"open", (PyCFunction)f_open, METH_KEYWORDS, f_open_doc},
1186     {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, f_addfont_doc},
1187     {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, f_addfontdir_doc},
1188     {"setparameter", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc},
1189     {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, f_verbose_doc},
1190
1191     /* devices */
1192     {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, f_createSWF_doc},
1193     {"OCR", (PyCFunction)f_createOCR, METH_KEYWORDS, f_createOCR_doc},
1194     {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, f_createImageList_doc},
1195     {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, f_createPlainText_doc},
1196     {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, f_createPassThrough_doc},
1197 #ifdef USE_OPENGL
1198     {"OpenGL", (PyCFunction)f_createOpenGL, METH_KEYWORDS, f_createOpenGL_doc},
1199 #endif
1200
1201     /* sentinel */
1202     {0, 0, 0, 0}
1203 };
1204
1205 PyDoc_STRVAR(gfx_doc, \
1206 "This module contains a PDF parser (based on xpdf) and a number of\n"
1207 "rendering backends. In particular, it can extract text from PDF pages,\n"
1208 "create bitmaps from them, or convert PDF files to SWF.\n" 
1209 "The latter functionality is similar to what is offered by swftools'\n" 
1210 "(http://www.swftools.org) pdf2swf utility, however more powerful-\n" 
1211 "You can also create individual SWF files from single pages of the PDF\n" 
1212 "or mix pages from different PDF files.\n"
1213 );
1214
1215 void initgfx(void)
1216 {
1217     initLog(0,0,0,0,0,2);
1218     OutputClass.ob_type = &PyType_Type;
1219     PageClass.ob_type = &PyType_Type;
1220     DocClass.ob_type = &PyType_Type;
1221
1222     pdfdriver = gfxsource_pdf_create();
1223     swfdriver = gfxsource_swf_create();
1224     imagedriver = gfxsource_image_create();
1225     
1226     PyObject*module = Py_InitModule3("gfx", pdf2swf_methods, gfx_doc);
1227     PyObject*module_dict = PyModule_GetDict(module);
1228
1229     PyDict_SetItemString(module_dict, "Doc", (PyObject*)&DocClass);
1230     PyDict_SetItemString(module_dict, "Page", (PyObject*)&PageClass);
1231     PyDict_SetItemString(module_dict, "Output", (PyObject*)&OutputClass);
1232 }