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