bb5ac9e7396a09fe7078aaff179502a0702a7427
[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 PyObject*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 PY_NONE;
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=='c') {
455             void* ptr = va_arg(ap, void*);
456             gfxcolor_t*col = (gfxcolor_t*)ptr;
457             PyObject*colobj = PyTuple_New(4);
458             PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->a));
459             PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->r));
460             PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->g));
461             PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->b));
462             PyTuple_SetItem(tuple, pos, colobj);
463         } else if(p=='l') {
464             void* ptr = va_arg(ap, void*);
465             gfxline_t*line = (gfxline_t*)ptr;
466             gfxline_t*l;
467             int len = 0, i = 0;
468             l = line;
469             while(l) {l=l->next;len++;}
470             PyObject*list = PyList_New(len);
471             l = line;
472             while(l) {
473                 PyObject*point=0;
474                 if(l->type == gfx_moveTo) {
475                     point = PyTuple_New(3);
476                     PyTuple_SetItem(point, 0, PyString_FromString("m"));
477                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
478                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
479                 } else if(l->type == gfx_lineTo) {
480                     point = PyTuple_New(3);
481                     PyTuple_SetItem(point, 0, PyString_FromString("l"));
482                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
483                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
484                 } else if(l->type == gfx_splineTo) {
485                     point = PyTuple_New(5);
486                     PyTuple_SetItem(point, 0, PyString_FromString("s"));
487                     PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
488                     PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
489                     PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sx));
490                     PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
491                 } else {
492                     point = PY_NONE;
493                 }
494                 PyList_SetItem(list, i, point);
495                 l = l->next;
496                 i++;
497             }
498             PyTuple_SetItem(tuple, pos, list);
499         } else {
500             PyTuple_SetItem(tuple, pos, PY_NONE);
501         }
502         pos++;
503     }
504     va_end(ap);
505     PyObject*f = PyObject_GetAttrString(self->pyobj, function);
506     if(!f)
507         return 0;
508     PyErr_Clear();
509     PyObject* result = PyObject_CallObject(f, tuple);
510
511     if(!result) { 
512         PyErr_Print();
513         PyErr_Clear();
514         return 0;
515     } else {
516         Py_DECREF(result);
517         return 0;
518     }
519 }
520     
521 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
522 {
523     callback_python("setparameter", dev, "ss", key, value);
524     return 1;
525 }
526 static void my_startpage(gfxdevice_t*dev, int width, int height)
527 {
528     callback_python("startpage", dev, "ii", width, height);
529 }
530 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
531 {
532     callback_python("startclip", dev, "l", line);
533 }
534 static void my_endclip(gfxdevice_t*dev)
535 {
536     callback_python("endclip", dev, "");
537 }
538 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)
539 {
540     char*cap = 0;
541     char*joint = 0;
542     if(cap_style == gfx_capButt)
543         cap = "butt";
544     else if(cap_style == gfx_capRound)
545         cap = "round";
546     else if(cap_style == gfx_capSquare)
547         cap = "square";
548     if(joint_style == gfx_joinMiter)
549         joint = "miter";
550     else if(joint_style == gfx_joinRound)
551         joint = "round";
552     else if(joint_style == gfx_joinBevel)
553         joint = "bevel";
554     callback_python("stroke", dev, "licssi", line, width, color, cap, joint, miterLimit);
555 }
556 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
557 {
558     callback_python("fill", dev, "lc", line, color);
559 }
560 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
561 {
562     callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
563 }
564 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
565 {
566     callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
567 }
568 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
569 {
570     callback_python("addfont", dev, "f", font);
571 }
572 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
573 {
574     callback_python("drawchar", dev, "ficm", font, glyph, color, matrix);
575 }
576 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
577 {
578     callback_python("drawlink", dev, "ls", line, action);
579 }
580 static void my_endpage(gfxdevice_t*dev)
581 {
582     callback_python("drawlink", dev, "");
583 }
584 static gfxresult_t* my_finish(gfxdevice_t*dev)
585 {
586     callback_python("finish", dev, "");
587     return 0;
588 }
589
590
591 PyDoc_STRVAR(f_createPassThrough_doc, \
592 "PassThrough(device)\n\n"
593 "Creates a PassThrough device, which can be used as parameter in calls\n"
594 "to page.render().\n"
595 "device needs to be a class implementing at least the following functions:\n\n"
596 "setparameter(key,value)\n"
597 "startclip(outline)\n"
598 "endclip()\n"
599 "stroke(outline, width, color, capstyle, jointstyle, miterLimit)\n"
600 "fill(outline, color)\n"
601 "fillbitmap(outline, image, matrix, colortransform)\n"
602 "fillgradient(outline, gradient, gradienttype, matrix)\n"
603 "addfont(font)\n"
604 "drawchar(font, glyph, color, matrix)\n"
605 "drawlink(outline, url)\n"
606 "If any of these functions are not defined, a error message will be printed,\n"
607 "however the rendering process will *not* be aborted.\n"
608 );
609 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
610 {
611     static char *kwlist[] = {"device", NULL};
612     PyObject*obj;
613     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
614         return NULL;
615     OutputObject*self = PyObject_New(OutputObject, &OutputClass);
616    
617     self->pyobj = obj;
618     Py_INCREF(obj);
619     self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
620     memset(self->output_device, 0, sizeof(gfxdevice_t));
621     self->output_device->name = strdup("passthrough");
622
623     self->output_device->setparameter = my_setparameter;
624     self->output_device->startpage = my_startpage;
625     self->output_device->startclip = my_startclip;
626     self->output_device->addfont = my_addfont;
627     self->output_device->endclip = my_endclip;
628     self->output_device->stroke = my_stroke;
629     self->output_device->fill = my_fill;
630     self->output_device->fillbitmap = my_fillbitmap;
631     self->output_device->fillgradient = my_fillgradient;
632     self->output_device->drawchar = my_drawchar;
633     self->output_device->drawlink = my_drawlink;
634     self->output_device->endpage = my_endpage;
635     self->output_device->finish = my_finish;
636     self->output_device->internal = self;
637
638     return (PyObject*)self;
639 }
640
641 static PyMethodDef output_methods[] =
642 {
643     /* Output functions */
644     {"save", (PyCFunction)output_save, METH_KEYWORDS, output_save_doc},
645     {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, output_startpage_doc},
646     {"fill", (PyCFunction)output_fill, METH_KEYWORDS, output_fill_doc},
647     {"fillbitmap", (PyCFunction)output_fillbitmap, METH_KEYWORDS, output_fillbitmap_doc},
648     {"stroke", (PyCFunction)output_stroke, METH_KEYWORDS, output_stroke_doc},
649     {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, output_endpage_doc},
650     {"setparameter", (PyCFunction)output_setparameter, METH_KEYWORDS, output_setparameter_doc},
651     {0,0,0,0}
652 };
653
654 static void output_dealloc(PyObject* _self) {
655     OutputObject* self = (OutputObject*)_self;
656
657     if(self->output_device) {
658         gfxresult_t*result = self->output_device->finish(self->output_device);
659         if(result) {
660             result->destroy(result);result=0;
661         }
662         self->output_device = 0;
663     }
664     
665     PyObject_Del(self);
666 }
667 static PyObject* output_getattr(PyObject * _self, char* a)
668 {
669     OutputObject*self = (OutputObject*)_self;
670    
671 /*    if(!strcmp(a, "x1")) {
672         return PyInt_FromLong(self->output_device->x1);
673     } else if(!strcmp(a, "y1")) {
674         return PyInt_FromLong(self->output_device->y1);
675     } else if(!strcmp(a, "x2")) {
676         return PyInt_FromLong(self->output_device->x2);
677     } else if(!strcmp(a, "y2")) {
678         return PyInt_FromLong(self->output_device->y2);
679     }*/
680     
681     return Py_FindMethod(output_methods, _self, a);
682 }
683 static int output_setattr(PyObject * _self, char* a, PyObject * o) 
684 {
685     OutputObject*self = (OutputObject*)_self;
686     if(!PyString_Check(o))
687         return -1;
688     char*value = PyString_AsString(o);
689     self->output_device->setparameter(self->output_device, a, value);
690     return -1;
691 }
692 static int output_print(PyObject * _self, FILE *fi, int flags)
693 {
694     OutputObject*self = (OutputObject*)_self;
695     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
696     return 0;
697 }
698
699 //---------------------------------------------------------------------
700 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
701 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
702
703 PyDoc_STRVAR(page_render_doc, \
704 "render(output, move=(0,0), clip=None)\n\n"
705 "Renders a page to the rendering backend specified by the output\n"
706 "parameter. Rendering consists of calling a number of functions on the\n"
707 "output device, see the description of the \"PassThrough\" device.\n"
708 "The page may be shifted to a given position using the move parameter,\n"
709 "and may also be clipped to a specific size using the clip parameter.\n"
710 "The clipping operation is applied after the move operation.\n"
711 );
712 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
713 {
714     PageObject* self = (PageObject*)_self; 
715     
716     static char *kwlist[] = {"dev", "move", "clip", NULL};
717     OutputObject*output = 0;
718     PyObject*move=0;
719     PyObject*clip=0;
720     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
721                 &move,&clip
722                 ))
723         return NULL;
724
725     int x=0,y=0;
726     int cx1=0,cy1=0,cx2=0,cy2=0;
727
728     if(move) {
729         if (!PyArg_ParseTuple(move, "ii", &x,&y))
730             return NULL;
731     }
732     if(clip) {
733         if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
734             return NULL;
735     }
736
737     if(x|y|cx1|cx2|cy1|cy2)
738         self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
739     else
740         self->page->render(self->page, output->output_device);
741     return PY_NONE;
742 }
743
744 PyDoc_STRVAR(page_asImage_doc, \
745 "asImage(width, height)\n\n"
746 "Creates a bitmap from a page. The bitmap will be returned as a string\n"
747 "containing RGB triplets. The bitmap will be rescaled to the specified width and\n"
748 "height. The aspect ratio of width and height doesn't need to be the same\n"
749 "as the page.\n"
750 );
751 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
752 {
753     PageObject* self = (PageObject*)_self; 
754     
755     static char *kwlist[] = {"width", "height", NULL};
756     int width=0,height=0;
757     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
758         return NULL;
759
760     if(!width || !height) {
761         return PY_ERROR("invalid dimensions: %dx%d", width,height);
762     }
763
764     gfxdevice_t dev1,dev2;
765     gfxdevice_render_init(&dev1);
766     dev1.setparameter(&dev1, "antialise", "2");
767     gfxdevice_rescale_init(&dev2, &dev1, width, height, 0);
768     dev2.startpage(&dev2, self->page->width, self->page->height);
769     self->page->render(self->page, &dev2);
770     dev2.endpage(&dev2);
771     gfxresult_t*result = dev2.finish(&dev2);
772     gfximage_t*img = (gfximage_t*)result->get(result,"page0");
773     int l = img->width*img->height;
774     unsigned char*data = (unsigned char*)malloc(img->width*img->height*3);
775     int s,t;
776     for(t=0,s=0;t<l;s+=3,t++) {
777         data[s+0] = img->data[t].r;
778         data[s+1] = img->data[t].g;
779         data[s+2] = img->data[t].b;
780     }
781     result->destroy(result);
782     return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
783 }
784
785 static PyMethodDef page_methods[] =
786 {
787     /* Page functions */
788     {"render", (PyCFunction)page_render, METH_KEYWORDS, page_render_doc},
789     {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, page_asImage_doc},
790     {0,0,0,0}
791 };
792 static void page_dealloc(PyObject* _self) {
793     PageObject* self = (PageObject*)_self; 
794     if(self->page) {
795         self->page->destroy(self->page);
796         self->page=0;
797     }
798     if(self->parent) {
799         Py_DECREF(self->parent);
800         self->parent=0;
801     }
802     
803     PyObject_Del(self);
804 }
805
806 static PyObject* page_getattr(PyObject * _self, char* a)
807 {
808     PageObject*self = (PageObject*)_self;
809     
810     if(!strcmp(a, "size")) {
811         return Py_BuildValue("(ii)", self->page->width, self->page->height);
812     } if(!strcmp(a, "doc")) {
813         Py_INCREF(self->parent);
814         return self->parent;
815     } if(!strcmp(a, "nr")) {
816         return PyInt_FromLong(self->nr);
817     } else if(!strcmp(a, "width")) {
818         return PyInt_FromLong(self->page->width);
819     } else if(!strcmp(a, "height")) {
820         return PyInt_FromLong(self->page->height);
821     }
822     return Py_FindMethod(page_methods, _self, a);
823 }
824
825 static int page_setattr(PyObject * self, char* a, PyObject * o) {
826     return -1;
827 }
828 static int page_print(PyObject * _self, FILE *fi, int flags)
829 {
830     PageObject*self = (PageObject*)_self;
831     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
832     return 0;
833 }
834
835 //---------------------------------------------------------------------
836
837 PyDoc_STRVAR(doc_getPage_doc,
838 "getPage(nr)\n\n"
839 "Get one page from a document file. The nr parameter specifies\n"
840 "which page to retrieve. Counting starts at 1, so the first page\n"
841 "can be retrieved by\n"
842 "    page = doc.getPage(1)\n"
843 ".\n"
844 "You can find out how many pages a document contains by querying\n"
845 "its pages field (doc.pages)\n"
846 );
847 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
848 {
849     DocObject* self = (DocObject*)_self;
850
851     static char *kwlist[] = {"nr", NULL};
852     int pagenr = 0;
853     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
854         return NULL;
855
856     PageObject*page = PyObject_New(PageObject, &PageClass);
857     page->page = self->doc->getpage(self->doc, pagenr);
858     page->nr = pagenr;
859     page->parent = _self;
860     Py_INCREF(page->parent);
861     if(!page->page) {
862         PyObject_Del(page);
863         return PY_ERROR("Couldn't extract page %d", pagenr);
864     }
865     return (PyObject*)page;
866 }
867
868 PyDoc_STRVAR(doc_getInfo_doc,
869 "getInfo(key)\n\n"
870 "Retrieve some information about a document. For PDF files, key\n"
871 "can have the following values:\n\n"
872 "\"title\", \"subject\", \"keywords\", \"author\", \"creator\", \"producer\",\n"
873 "\"creationdate\", \"moddate\", \"linearized\", \"tagged\", \"encrypted\",\n"
874 "\"oktoprint\", \"oktocopy\", \"oktochange\", \"oktoaddnotes\", \"version\".\n\n"
875 "If the \"oktocopy\" digital rights management flag is set to \"no\", then the\n"
876 "pdf parser won't allow you to access the PDF file. Trying to extract pages\n"
877 "from it will raise an exception.\n"
878 );
879 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
880 {
881     DocObject* self = (DocObject*)_self;
882
883     static char *kwlist[] = {"key", NULL};
884     char*key = 0;
885     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
886         return NULL;
887
888     char*s = self->doc->getinfo(self->doc, key);
889     return PyString_FromString(s);
890 }
891
892 PyDoc_STRVAR(doc_setparameter_doc,
893 "setparameter(key, value)\n\n"
894 "Pass a parameter or setting to the document parser. Unlike\n"
895 "the module level setparameter() function, the parameters set\n"
896 "using setparameter will only be valid for the object itself\n"
897 "during its lifetime.\n"
898 );
899 static PyObject* doc_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
900 {
901     DocObject* self = (DocObject*)_self;
902
903     static char *kwlist[] = {"key", "value", NULL};
904     char*key = 0, *value=0;
905     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
906         return NULL;
907
908     self->doc->set_parameter(self->doc, key, value);
909     return PY_NONE;
910 }
911
912 PyDoc_STRVAR(f_open_doc,
913 "open(type, filename) -> object\n\n"
914 "Open a PDF, SWF or image file. The type argument should be \"pdf\",\n"
915 "\"swf\" or \"image\" accordingly. It returns a doc object which can be\n"
916 "used to process the file contents.\n"
917 "E.g.\n"
918 "    doc = open(\"pdf\", \"document.pdf\")\n"
919 "    doc = open(\"swf\", \"flashfile.swf\")\n"
920 "    doc = open(\"image\", \"image.png\")\n"
921 "If the file could not be loaded, or is a encrypted PDF file without\n"
922 "a proper password specified, an exception is being raised.\n"
923 "If the filename argument contains a '|' char, everything behind\n"
924 "the '|' is treated as password used for opening the file.\n"
925 "E.g.\n"
926 "    doc = open(\"pdf\", \"document.pdf|mysecretpassword\")\n"
927 ".\n"
928 "Notice that for image files, the only supported file formats right now\n"
929 "are jpeg and png.\n"
930 );
931 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
932 {
933     static char *kwlist[] = {"type", "filename", NULL};
934     char*filename=0;
935     char*type=0;
936     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename)) {
937         static char *kwlist2[] = {"filename", NULL};
938         type = 0;
939         PyErr_Clear();
940         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist2, &filename))
941             return NULL;
942     }
943
944     DocObject*self = PyObject_New(DocObject, &DocClass);
945
946     if(!type) { //autodetect
947         type = "pdf"; //default
948         int l = strlen(filename);
949         if(l>4) {
950             if(filename[l-4]=='.') {
951                 if(strchr("pP", filename[l-3]) && strchr("dD", filename[l-2]) && strchr("fF", filename[l-1]))
952                     type = "pdf";
953                 if(strchr("jJ", filename[l-3]) && strchr("pP", filename[l-2]) && strchr("gG", filename[l-1]))
954                     type = "image";
955                 if(strchr("pP", filename[l-3]) && strchr("nN", filename[l-2]) && strchr("gG", filename[l-1]))
956                     type = "image";
957                 if(strchr("sS", filename[l-3]) && strchr("wW", filename[l-2]) && strchr("fF", filename[l-1]))
958                     type = "swf";
959             } else if(filename[l-5]=='.') {
960                 type = "image";
961             }
962         }
963     }
964    
965     if(!strcmp(type,"pdf"))
966         self->doc = pdfdriver->open(pdfdriver,filename);
967     else if(!strcmp(type, "image") || !strcmp(type, "img"))  
968         self->doc = imagedriver->open(imagedriver, filename);
969     else if(!strcmp(type, "swf") || !strcmp(type, "SWF"))
970         self->doc = swfdriver->open(imagedriver, filename);
971     else
972         return PY_ERROR("Unknown type %s", type);
973
974     if(!self->doc) {
975         PyObject_Del(self);
976         return PY_ERROR("Couldn't open %s", filename);
977     }
978     self->filename = strdup(filename);
979     return (PyObject*)self;
980 }
981
982 static PyMethodDef doc_methods[] =
983 {
984     /* PDF functions */
985     {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, doc_getPage_doc},
986     {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, doc_getInfo_doc},
987     {"setparameter", (PyCFunction)doc_setparameter, METH_KEYWORDS, doc_setparameter_doc},
988     {0,0,0,0}
989 };
990
991 static void doc_dealloc(PyObject* _self) {
992     DocObject* self = (DocObject*)_self;
993     if(self->doc) {
994         self->doc->destroy(self->doc);
995         self->doc=0;
996     }
997     if(self->filename) {
998         free(self->filename);self->filename=0;
999     }
1000     PyObject_Del(self);
1001 }
1002 static PyObject* doc_getattr(PyObject * _self, char* a)
1003 {
1004     DocObject*self = (DocObject*)_self;
1005     if(!strcmp(a, "pages")) {
1006         return PyInt_FromLong(self->doc->num_pages);
1007     }
1008     if(!strcmp(a, "filename")) {
1009         return PyString_FromString(self->filename);
1010     }
1011     return Py_FindMethod(doc_methods, _self, a);
1012 }
1013 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
1014     return -1;
1015 }
1016 static int doc_print(PyObject * _self, FILE *fi, int flags)
1017 {
1018     DocObject*self = (DocObject*)_self;
1019     fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
1020     return 0;
1021 }
1022
1023 //---------------------------------------------------------------------
1024
1025 PyDoc_STRVAR(output_doc,
1026 "An Output object can be used as parameter to the render()\n"
1027 "call of a page. It's not possible to create this type of\n"
1028 "object directly (i.e., from a class), however you can\n"
1029 "use a PassThrough() device to pass things over to Python.\n"
1030 "Examples for classes implementing the Output class are: \n"
1031 "ImageList, SWF, PlainText and PassThrough.\n"
1032 );
1033 static PyTypeObject OutputClass =
1034 {
1035     PyObject_HEAD_INIT(NULL)
1036     0,
1037     tp_name: "gfx.Output",
1038     tp_basicsize: sizeof(OutputObject),
1039     tp_itemsize: 0,
1040     tp_dealloc: output_dealloc,
1041     tp_print: output_print,
1042     tp_getattr: output_getattr,
1043     tp_setattr: output_setattr,
1044     tp_doc: output_doc,
1045     tp_methods: output_methods
1046 };
1047 PyDoc_STRVAR(page_doc,
1048 "A Page object contains a single page of a document.\n"
1049 "page.width and page.height (or page.size) contain the\n"
1050 "page dimensions. page.nr is the number of the page, and\n"
1051 "page.doc is the parent document.\n"
1052 );
1053 static PyTypeObject PageClass =
1054 {
1055     PyObject_HEAD_INIT(NULL)
1056     0,
1057     tp_name: "gfx.Page",
1058     tp_basicsize: sizeof(PageObject),
1059     tp_itemsize: 0,
1060     tp_dealloc: page_dealloc,
1061     tp_print: page_print,
1062     tp_getattr: page_getattr,
1063     tp_setattr: page_setattr,
1064     tp_doc: page_doc,
1065     tp_methods: page_methods
1066 };
1067 PyDoc_STRVAR(doc_doc,
1068 "A Doc object is used for storing a document (like a PDF).\n"
1069 "doc.pages contains the number of pages in the document,\n"
1070 "and doc.filename the name of the file the document was\n"
1071 "created (loaded) from. If the document was created from\n"
1072 "an image file, the number of pages is always 1\n"
1073 );
1074 static PyTypeObject DocClass =
1075 {
1076     PyObject_HEAD_INIT(NULL)
1077     0,
1078     tp_name: "gfx.Doc",
1079     tp_basicsize: sizeof(DocObject),
1080     tp_itemsize: 0,
1081     tp_dealloc: doc_dealloc,
1082     tp_print: doc_print,
1083     tp_getattr: doc_getattr,
1084     tp_setattr: doc_setattr,
1085     tp_doc: doc_doc,
1086     tp_methods: doc_methods,
1087 };
1088
1089 //=====================================================================
1090
1091 PyDoc_STRVAR(f_setparameter_doc, \
1092 "setparameter(key,value)\n\n"
1093 "Set a parameter in the gfx module (which might affect the PDF\n"
1094 "parser or any of the rendering backends). This is a parameter\n"
1095 "which would usually be passed with the \"-s\" option to pdf2swf.\n"
1096 "For a list of all parameters, see the output of\n"
1097 "    pdf2swf -s help\n"
1098 "and\n"
1099 "    pdf2swf somefile.pdf -s help\n"
1100 ".\n"
1101 );
1102 static PyObject* f_setparameter(PyObject* self, PyObject* args, PyObject* kwargs)
1103 {
1104     static char *kwlist[] = {"key", "value", NULL};
1105     char*key=0,*value=0;
1106     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
1107         return NULL;
1108     pdfdriver->set_parameter(pdfdriver,key,value);
1109     return PY_NONE;
1110 }
1111
1112 PyDoc_STRVAR(f_verbose_doc, \
1113 "verbose(level)\n\n"
1114 "Set the logging verbosity of the gfx module. Log levels are:\n"
1115 "level=-1          Log nothing\n"
1116 "level=0 (fatal)   Log only fatal errors\n"
1117 "level=1 (error)   Log only fatal errors and errors\n"
1118 "level=2 (warn)    Log all errors and warnings\n"
1119 "level=3 (notice)  Log also some rudimentary data about the parsing/conversion\n"
1120 "level=4 (verbose) Log some additional parsing information\n"
1121 "level=5 (debug)   Log debug statements\n"
1122 "level=6 (trace)   Log extended debug statements\n"
1123 "All logging messages are written to stdout.\n"
1124 );
1125 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
1126 {
1127     static char *kwlist[] = {"val", NULL};
1128     int val;
1129     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
1130         return NULL;
1131     setConsoleLogging(val);
1132     return PY_NONE;
1133 }
1134
1135 PyDoc_STRVAR(f_addfont_doc, \
1136 "addfont(filename)\n\n"
1137 "Passes an additional font file to the PDF parser. If a PDF contains\n"
1138 "external fonts (i.e. fonts which are not contained in the PDF itself)\n"
1139 "then the files added by addfont() will be searched.\n"
1140 );
1141
1142 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
1143 {
1144     static char *kwlist[] = {"filename", NULL};
1145     char*filename=0;
1146     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
1147         return NULL;
1148     pdfdriver->set_parameter(pdfdriver,"font", filename);
1149     return PY_NONE;
1150 }
1151
1152 PyDoc_STRVAR(f_addfontdir_doc, \
1153 "addfontdir(dirname)\n\n"
1154 "Passes a complete directory containing fonts to the PDF parser. Any\n"
1155 "font file within this directory might be used to resolve external fonts\n"
1156 "in PDF files\n"
1157 );
1158 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
1159 {
1160     static char *kwlist[] = {"filename", NULL};
1161     char*filename=0;
1162     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
1163         return NULL;
1164     pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
1165     return PY_NONE;
1166 }
1167
1168 static PyMethodDef pdf2swf_methods[] =
1169 {
1170     /* sources */
1171     {"open", (PyCFunction)f_open, METH_KEYWORDS, f_open_doc},
1172     {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, f_addfont_doc},
1173     {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, f_addfontdir_doc},
1174     {"setparameter", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc},
1175     {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, f_verbose_doc},
1176
1177     /* devices */
1178     {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, f_createSWF_doc},
1179     {"OCR", (PyCFunction)f_createOCR, METH_KEYWORDS, f_createOCR_doc},
1180     {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, f_createImageList_doc},
1181     {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, f_createPlainText_doc},
1182     {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, f_createPassThrough_doc},
1183 #ifdef USE_OPENGL
1184     {"OpenGL", (PyCFunction)f_createOpenGL, METH_KEYWORDS, f_createOpenGL_doc},
1185 #endif
1186
1187     /* sentinel */
1188     {0, 0, 0, 0}
1189 };
1190
1191 PyDoc_STRVAR(gfx_doc, \
1192 "This module contains a PDF parser (based on xpdf) and a number of\n"
1193 "rendering backends. In particular, it can extract text from PDF pages,\n"
1194 "create bitmaps from them, or convert PDF files to SWF.\n" 
1195 "The latter functionality is similar to what is offered by swftools'\n" 
1196 "(http://www.swftools.org) pdf2swf utility, however more powerful-\n" 
1197 "You can also create individual SWF files from single pages of the PDF\n" 
1198 "or mix pages from different PDF files.\n"
1199 );
1200
1201 void initgfx(void)
1202 {
1203     initLog(0,0,0,0,0,2);
1204     OutputClass.ob_type = &PyType_Type;
1205     PageClass.ob_type = &PyType_Type;
1206     DocClass.ob_type = &PyType_Type;
1207
1208     pdfdriver = gfxsource_pdf_create();
1209     swfdriver = gfxsource_swf_create();
1210     imagedriver = gfxsource_image_create();
1211     
1212     PyObject*module = Py_InitModule3("gfx", pdf2swf_methods, gfx_doc);
1213     PyObject*module_dict = PyModule_GetDict(module);
1214
1215     PyDict_SetItemString(module_dict, "Doc", (PyObject*)&DocClass);
1216     PyDict_SetItemString(module_dict, "Page", (PyObject*)&PageClass);
1217     PyDict_SetItemString(module_dict, "Output", (PyObject*)&OutputClass);
1218 }