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