3 Python wrapper for gfx convert
5 Part of the swftools package.
7 Copyright (c) 2003 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
26 #include "../devices/swf.h"
27 #include "../devices/render.h"
28 #include "../devices/rescale.h"
29 #include "../devices/text.h"
30 #include "../pdf/pdf.h"
31 #include "../readers/swf.h"
32 #include "../readers/image.h"
36 static gfxsource_t*pdfdriver = 0;
37 static gfxsource_t*swfdriver = 0;
38 static gfxsource_t*imagedriver = 0;
40 staticforward PyTypeObject OutputClass;
41 staticforward PyTypeObject PageClass;
42 staticforward PyTypeObject DocClass;
46 gfxdevice_t*output_device;
47 PyObject*pyobj; //only for passthrough
63 static char* strf(char*format, ...)
68 va_start(arglist, format);
69 vsprintf(buf, format, arglist);
73 #define PY_ERROR(s,args...) (PyErr_SetString(PyExc_Exception, strf(s, ## args)),NULL)
74 #define PY_NONE Py_BuildValue("s", 0)
76 //---------------------------------------------------------------------
77 PyDoc_STRVAR(output_save_doc, \
79 "Saves the contents of an output device to a file\n"
80 "Depending on what the output device is, the contents\n"
81 "of the file may be plain text, an image, an SWF file,\n"
83 "For the ImageList device, several files (named\n"
84 "filename.1.png, filename.2.png etc.) might be created)\n"
86 static PyObject* output_save(PyObject* _self, PyObject* args, PyObject* kwargs)
88 OutputObject* self = (OutputObject*)_self;
90 static char *kwlist[] = {"filename", NULL};
91 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
94 gfxresult_t*result = self->output_device->finish(self->output_device);
95 self->output_device = 0;
96 if(result->save(result, filename) < 0) {
97 return PY_ERROR("Couldn't write to %s", filename);
99 result->destroy(result);
103 PyDoc_STRVAR(output_startpage_doc, \
104 "startpage(width, height)\n\n"
105 "Starts a new page/frame in the output device.\n"
106 "The usual way to render documents is to start a new page in the\n"
107 "device for each page in the document:\n"
109 "for pagenr in range(1,doc.pages+1):\n"
110 " page = doc.getPage(pagenr)\n"
111 " output.startpage(page.width, page.height)\n"
112 " page.render(output)\n"
113 " output.endpage()\n"
115 "It is, however, also possible to render more than one document page\n"
116 "to a single output page. E.g. for side-by-side or book views.\n"
118 static PyObject* output_startpage(PyObject* _self, PyObject* args, PyObject* kwargs)
120 OutputObject* self = (OutputObject*)_self;
121 int width=0, height=0;
122 if (!PyArg_ParseTuple(args, "ii", &width, &height))
124 self->output_device->startpage(self->output_device, width, height);
127 PyDoc_STRVAR(output_endpage_doc, \
129 "Ends a page in the output device. This function should be called\n"
130 "once for every startpage()\n"
132 static PyObject* output_endpage(PyObject* _self, PyObject* args, PyObject* kwargs)
134 OutputObject* self = (OutputObject*)_self;
135 if (!PyArg_ParseTuple(args, ""))
137 self->output_device->endpage(self->output_device);
140 PyDoc_STRVAR(output_setparameter_doc, \
141 "setparameter(key, value)\n\n"
142 "Set a output-device dependent parameter"
144 static PyObject* output_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
146 OutputObject* self = (OutputObject*)_self;
147 static char *kwlist[] = {"key", "value", NULL};
149 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
151 self->output_device->setparameter(self->output_device, key, value);
154 PyDoc_STRVAR(f_createSWF_doc, \
156 "Creates a device which renders documents to SWF (Flash) files.\n"
157 "Depending on the way the document parser behaves (see the poly2bitmap\n"
158 "and bitmap parameters), the resulting SWF might use vector operations\n"
159 "and Flash Texts to display the document, or just a single bitmap.\n"
161 static PyObject* f_createSWF(PyObject* parent, PyObject* args, PyObject* kwargs)
163 static char *kwlist[] = {NULL};
164 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
166 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
168 self->output_device = malloc(sizeof(gfxdevice_t));
169 gfxdevice_swf_init(self->output_device);
170 return (PyObject*)self;
173 PyDoc_STRVAR(f_createImageList_doc, \
175 "Creates a device which renders documents to bitmaps.\n"
176 "Each page that is rendered will create new bitmap.\n"
177 "Using save(), you can save the images to a number\n"
180 static PyObject* f_createImageList(PyObject* parent, PyObject* args, PyObject* kwargs)
182 static char *kwlist[] = {NULL};
183 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
185 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
187 self->output_device = malloc(sizeof(gfxdevice_t));
188 gfxdevice_render_init(self->output_device);
189 return (PyObject*)self;
192 PyDoc_STRVAR(f_createPlainText_doc, \
194 "Creates a device which can be used to extract text from documents,\n"
195 "by passing it as parameter to page.render().\n"
196 "The extracted text can be saved by plaintext.save(filename).\n"
198 static PyObject* f_createPlainText(PyObject* parent, PyObject* args, PyObject* kwargs)
200 static char *kwlist[] = {NULL};
201 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
203 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
205 self->output_device = malloc(sizeof(gfxdevice_t));
206 gfxdevice_text_init(self->output_device);
207 return (PyObject*)self;
210 static PyObject*callback_python(char*function, gfxdevice_t*dev, const char*format, ...)
212 OutputObject*self = (OutputObject*)dev->internal;
214 if(!PyObject_HasAttrString(self->pyobj, function))
218 va_start(ap, format);
220 PyObject*tuple = PyTuple_New(strlen(format));
223 char p = format[pos];
225 char*s = va_arg(ap, char*);
226 PyTuple_SetItem(tuple, pos, PyString_FromString(s));
228 int i = va_arg(ap, int);
229 PyTuple_SetItem(tuple, pos, PyInt_FromLong(i));
231 void* ptr = va_arg(ap, void*);
232 gfxcolor_t*col = (gfxcolor_t*)ptr;
233 PyObject*colobj = PyTuple_New(4);
234 PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->r));
235 PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->g));
236 PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->b));
237 PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->a));
238 PyTuple_SetItem(tuple, pos, colobj);
240 void* ptr = va_arg(ap, void*);
241 gfxline_t*line = (gfxline_t*)ptr;
245 while(l) {l=l->next;len++;}
246 PyObject*list = PyList_New(len);
250 if(l->type == gfx_moveTo) {
251 point = PyTuple_New(3);
252 PyTuple_SetItem(point, 0, PyString_FromString("m"));
253 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
254 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
255 } else if(l->type == gfx_lineTo) {
256 point = PyTuple_New(3);
257 PyTuple_SetItem(point, 0, PyString_FromString("l"));
258 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
259 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
260 } else if(l->type == gfx_splineTo) {
261 point = PyTuple_New(5);
262 PyTuple_SetItem(point, 0, PyString_FromString("s"));
263 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
264 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
265 PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sx));
266 PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
270 PyList_SetItem(list, i, point);
274 PyTuple_SetItem(tuple, pos, list);
276 PyTuple_SetItem(tuple, pos, PY_NONE);
281 PyObject*f = PyObject_GetAttrString(self->pyobj, function);
285 PyObject* result = PyObject_CallObject(f, tuple);
297 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
299 callback_python("setparameter", dev, "ss", key, value);
302 static void my_startpage(gfxdevice_t*dev, int width, int height)
304 callback_python("startpage", dev, "ii", width, height);
306 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
308 callback_python("startclip", dev, "l", line);
310 static void my_endclip(gfxdevice_t*dev)
312 callback_python("endclip", dev, "");
314 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)
318 if(cap_style == gfx_capButt)
320 else if(cap_style == gfx_capRound)
322 else if(cap_style == gfx_capSquare)
324 if(joint_style == gfx_joinMiter)
326 else if(joint_style == gfx_joinRound)
328 else if(joint_style == gfx_joinBevel)
330 callback_python("stroke", dev, "licssi", line, width, color, cap, joint, miterLimit);
332 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
334 callback_python("fill", dev, "lc", line, color);
336 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
338 callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
340 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
342 callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
344 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
346 callback_python("addfont", dev, "f", font);
348 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
350 callback_python("drawchar", dev, "ficm", font, glyph, color, matrix);
352 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
354 callback_python("drawlink", dev, "ls", line, action);
356 static void my_endpage(gfxdevice_t*dev)
358 callback_python("drawlink", dev, "");
360 static gfxresult_t* my_finish(gfxdevice_t*dev)
362 callback_python("finish", dev, "");
367 PyDoc_STRVAR(f_createPassThrough_doc, \
368 "PassThrough(device)\n\n"
369 "Creates a PassThrough device, which can be used as parameter in calls\n"
370 "to page.render().\n"
371 "device needs to be a class implementing at least the following functions:\n\n"
372 "setparameter(key,value)\n"
373 "startclip(outline)\n"
375 "stroke(outline, width, color, capstyle, jointstyle, miterLimit)\n"
376 "fill(outline, color)\n"
377 "fillbitmap(outline, image, matrix, colortransform)\n"
378 "fillgradient(outline, gradient, gradienttype, matrix)\n"
380 "drawchar(font, glyph, color, matrix)\n"
381 "drawlink(outline, url)\n"
382 "If any of these functions are not defined, a error message will be printed,\n"
383 "however the rendering process will *not* be aborted.\n"
385 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
387 static char *kwlist[] = {"device", NULL};
389 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
391 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
394 self->output_device = malloc(sizeof(gfxdevice_t));
395 memset(self->output_device, 0, sizeof(gfxdevice_t));
396 self->output_device->name = strdup("passthrough");
398 self->output_device->setparameter = my_setparameter;
399 self->output_device->startpage = my_startpage;
400 self->output_device->startclip = my_startclip;
401 self->output_device->addfont = my_addfont;
402 self->output_device->endclip = my_endclip;
403 self->output_device->stroke = my_stroke;
404 self->output_device->fill = my_fill;
405 self->output_device->fillbitmap = my_fillbitmap;
406 self->output_device->fillgradient = my_fillgradient;
407 self->output_device->drawchar = my_drawchar;
408 self->output_device->drawlink = my_drawlink;
409 self->output_device->endpage = my_endpage;
410 self->output_device->finish = my_finish;
411 self->output_device->internal = self;
413 return (PyObject*)self;
416 static PyMethodDef output_methods[] =
418 /* Output functions */
419 {"save", (PyCFunction)output_save, METH_KEYWORDS, output_save_doc},
420 {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, output_startpage_doc},
421 {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, output_endpage_doc},
422 {"setparameter", (PyCFunction)output_setparameter, METH_KEYWORDS, output_setparameter_doc},
426 static void output_dealloc(PyObject* _self) {
427 OutputObject* self = (OutputObject*)_self;
429 if(self->output_device) {
430 gfxresult_t*result = self->output_device->finish(self->output_device);
432 result->destroy(result);result=0;
434 self->output_device = 0;
439 static PyObject* output_getattr(PyObject * _self, char* a)
441 OutputObject*self = (OutputObject*)_self;
443 /* if(!strcmp(a, "x1")) {
444 return PyInt_FromLong(self->output_device->x1);
445 } else if(!strcmp(a, "y1")) {
446 return PyInt_FromLong(self->output_device->y1);
447 } else if(!strcmp(a, "x2")) {
448 return PyInt_FromLong(self->output_device->x2);
449 } else if(!strcmp(a, "y2")) {
450 return PyInt_FromLong(self->output_device->y2);
453 return Py_FindMethod(output_methods, _self, a);
455 static int output_setattr(PyObject * _self, char* a, PyObject * o)
457 OutputObject*self = (OutputObject*)_self;
458 if(!PyString_Check(o))
460 char*value = PyString_AsString(o);
461 self->output_device->setparameter(self->output_device, a, value);
464 static int output_print(PyObject * _self, FILE *fi, int flags)
466 OutputObject*self = (OutputObject*)_self;
467 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
471 //---------------------------------------------------------------------
472 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
473 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
475 PyDoc_STRVAR(page_render_doc, \
476 "render(output, move=(0,0), clip=None)\n\n"
477 "Renders a page to the rendering backend specified by the output\n"
478 "parameter. Rendering consists of calling a number of functions on the\n"
479 "output device, see the description of the \"PassThrough\" device.\n"
480 "The page may be shifted to a given position using the move parameter,\n"
481 "and may also be clipped to a specific size using the clip parameter.\n"
482 "The clipping operation is applied after the move operation.\n"
484 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
486 PageObject* self = (PageObject*)_self;
488 static char *kwlist[] = {"dev", "move", "clip", NULL};
489 OutputObject*output = 0;
492 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
498 int cx1=0,cy1=0,cx2=0,cy2=0;
501 if (!PyArg_ParseTuple(move, "ii", &x,&y))
505 if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
509 if(x|y|cx1|cx2|cy1|cy2)
510 self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
512 self->page->render(self->page, output->output_device);
516 PyDoc_STRVAR(page_asImage_doc, \
517 "asImage(width, height)\n\n"
518 "Creates a bitmap from a page. The bitmap will be returned as a string\n"
519 "containing RGB triplets. The bitmap will be rescaled to the specified width and\n"
520 "height. The aspect ratio of width and height doesn't need to be the same\n"
523 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
525 PageObject* self = (PageObject*)_self;
527 static char *kwlist[] = {"width", "height", NULL};
528 int width=0,height=0;
529 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
532 if(!width || !height) {
533 return PY_ERROR("invalid dimensions: %dx%d", width,height);
536 gfxdevice_t dev1,dev2;
537 gfxdevice_render_init(&dev1);
538 dev1.setparameter(&dev1, "antialise", "2");
539 gfxdevice_rescale_init(&dev2, &dev1, width, height, 0);
540 dev2.startpage(&dev2, self->page->width, self->page->height);
541 self->page->render(self->page, &dev2);
543 gfxresult_t*result = dev2.finish(&dev2);
544 gfximage_t*img = (gfximage_t*)result->get(result,"page0");
545 int l = img->width*img->height;
546 unsigned char*data = malloc(img->width*img->height*3);
548 for(t=0,s=0;t<l;s+=3,t++) {
549 data[s+0] = img->data[t].r;
550 data[s+1] = img->data[t].g;
551 data[s+2] = img->data[t].b;
553 result->destroy(result);
554 return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
557 static PyMethodDef page_methods[] =
560 {"render", (PyCFunction)page_render, METH_KEYWORDS, page_render_doc},
561 {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, page_asImage_doc},
564 static void page_dealloc(PyObject* _self) {
565 PageObject* self = (PageObject*)_self;
567 self->page->destroy(self->page);
571 Py_DECREF(self->parent);
578 static PyObject* page_getattr(PyObject * _self, char* a)
580 PageObject*self = (PageObject*)_self;
582 if(!strcmp(a, "size")) {
583 return Py_BuildValue("(ii)", self->page->width, self->page->height);
584 } if(!strcmp(a, "doc")) {
585 Py_INCREF(self->parent);
587 } if(!strcmp(a, "nr")) {
588 return PyInt_FromLong(self->nr);
589 } else if(!strcmp(a, "width")) {
590 return PyInt_FromLong(self->page->width);
591 } else if(!strcmp(a, "height")) {
592 return PyInt_FromLong(self->page->height);
594 return Py_FindMethod(page_methods, _self, a);
597 static int page_setattr(PyObject * self, char* a, PyObject * o) {
600 static int page_print(PyObject * _self, FILE *fi, int flags)
602 PageObject*self = (PageObject*)_self;
603 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
607 //---------------------------------------------------------------------
609 PyDoc_STRVAR(doc_getPage_doc,
611 "Get one page from a document file. The nr parameter specifies\n"
612 "which page to retrieve. Counting starts at 1, so the first page\n"
613 "can be retrieved by\n"
614 " page = doc.getPage(1)\n"
616 "You can find out how many pages a document contains by querying\n"
617 "its pages field (doc.pages)\n"
619 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
621 DocObject* self = (DocObject*)_self;
623 static char *kwlist[] = {"nr", NULL};
625 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
628 PageObject*page = PyObject_New(PageObject, &PageClass);
629 page->page = self->doc->getpage(self->doc, pagenr);
631 page->parent = _self;
632 Py_INCREF(page->parent);
635 return PY_ERROR("Couldn't extract page %d", pagenr);
637 return (PyObject*)page;
640 PyDoc_STRVAR(doc_getInfo_doc,
642 "Retrieve some information about a document. For PDF files, key\n"
643 "can have the following values:\n\n"
644 "\"title\", \"subject\", \"keywords\", \"author\", \"creator\", \"producer\",\n"
645 "\"creationdate\", \"moddate\", \"linearized\", \"tagged\", \"encrypted\",\n"
646 "\"oktoprint\", \"oktocopy\", \"oktochange\", \"oktoaddnotes\", \"version\".\n\n"
647 "If the \"oktocopy\" digital rights management flag is set to \"no\", then the\n"
648 "pdf parser won't allow you to access the PDF file. Trying to extract pages\n"
649 "from it will raise an exception.\n"
651 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
653 DocObject* self = (DocObject*)_self;
655 static char *kwlist[] = {"key", NULL};
657 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
660 char*s = self->doc->getinfo(self->doc, key);
661 return PyString_FromString(s);
664 PyDoc_STRVAR(doc_setparameter_doc,
665 "setparameter(key, value)\n\n"
666 "Pass a parameter or setting to the document parser. Unlike\n"
667 "the module level setparameter() function, the parameters set\n"
668 "using setparameter will only be valid for the object itself\n"
669 "during its lifetime.\n"
671 static PyObject* doc_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
673 DocObject* self = (DocObject*)_self;
675 static char *kwlist[] = {"key", "value", NULL};
676 char*key = 0, *value=0;
677 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
680 self->doc->set_parameter(self->doc, key, value);
684 PyDoc_STRVAR(f_open_doc,
685 "open(type, filename) -> object\n\n"
686 "Open a PDF, SWF or image file. The type argument should be \"pdf\",\n"
687 "\"swf\" or \"image\" accordingly. It returns a doc object which can be\n"
688 "used to process the file contents.\n"
690 " doc = open(\"pdf\", \"document.pdf\")\n"
691 " doc = open(\"swf\", \"flashfile.swf\")\n"
692 " doc = open(\"image\", \"image.png\")\n"
693 "If the file could not be loaded, or is a encrypted PDF file without\n"
694 "a proper password specified, an exception is being raised.\n"
695 "If the filename argument contains a '|' char, everything behind\n"
696 "the '|' is treated as password used for opening the file.\n"
698 " doc = open(\"pdf\", \"document.pdf|mysecretpassword\")\n"
700 "Notice that for image files, the only supported file formats right now\n"
701 "are jpeg and png.\n"
703 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
705 static char *kwlist[] = {"type", "filename", NULL};
708 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename)) {
709 static char *kwlist2[] = {"filename", NULL};
712 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist2, &filename))
716 DocObject*self = PyObject_New(DocObject, &DocClass);
718 if(!type) { //autodetect
719 type = "pdf"; //default
720 int l = strlen(filename);
722 if(filename[l-4]=='.') {
723 if(strchr("pP", filename[l-3]) && strchr("dD", filename[l-2]) && strchr("fF", filename[l-1]))
725 if(strchr("jJ", filename[l-3]) && strchr("pP", filename[l-2]) && strchr("gG", filename[l-1]))
727 if(strchr("pP", filename[l-3]) && strchr("nN", filename[l-2]) && strchr("gG", filename[l-1]))
729 if(strchr("sS", filename[l-3]) && strchr("wW", filename[l-2]) && strchr("fF", filename[l-1]))
731 } else if(filename[l-5]=='.') {
737 if(!strcmp(type,"pdf"))
738 self->doc = pdfdriver->open(pdfdriver,filename);
739 else if(!strcmp(type, "image") || !strcmp(type, "img"))
740 self->doc = imagedriver->open(imagedriver, filename);
741 else if(!strcmp(type, "swf") || !strcmp(type, "SWF"))
742 self->doc = swfdriver->open(imagedriver, filename);
744 return PY_ERROR("Unknown type %s", type);
748 return PY_ERROR("Couldn't open %s", filename);
750 self->filename = strdup(filename);
751 return (PyObject*)self;
754 static PyMethodDef doc_methods[] =
757 {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, doc_getPage_doc},
758 {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, doc_getInfo_doc},
759 {"setparameter", (PyCFunction)doc_setparameter, METH_KEYWORDS, doc_setparameter_doc},
763 static void doc_dealloc(PyObject* _self) {
764 DocObject* self = (DocObject*)_self;
766 self->doc->destroy(self->doc);
770 free(self->filename);self->filename=0;
774 static PyObject* doc_getattr(PyObject * _self, char* a)
776 DocObject*self = (DocObject*)_self;
777 if(!strcmp(a, "pages")) {
778 return PyInt_FromLong(self->doc->num_pages);
780 if(!strcmp(a, "filename")) {
781 return PyString_FromString(self->filename);
783 return Py_FindMethod(doc_methods, _self, a);
785 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
788 static int doc_print(PyObject * _self, FILE *fi, int flags)
790 DocObject*self = (DocObject*)_self;
791 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
795 //---------------------------------------------------------------------
797 PyDoc_STRVAR(output_doc,
798 "An Output object can be used as parameter to the render()\n"
799 "call of a page. It's not possible to create this type of\n"
800 "object directly (i.e., from a class), however you can\n"
801 "use a PassThrough() device to pass things over to Python.\n"
802 "Examples for classes implementing the Output class are: \n"
803 "ImageList, SWF, PlainText and PassThrough.\n"
805 static PyTypeObject OutputClass =
807 PyObject_HEAD_INIT(NULL)
809 tp_name: "gfx.Output",
810 tp_basicsize: sizeof(OutputObject),
812 tp_dealloc: output_dealloc,
813 tp_print: output_print,
814 tp_getattr: output_getattr,
815 tp_setattr: output_setattr,
817 tp_methods: output_methods
819 PyDoc_STRVAR(page_doc,
820 "A Page object contains a single page of a document.\n"
821 "page.width and page.height (or page.size) contain the\n"
822 "page dimensions. page.nr is the number of the page, and\n"
823 "page.doc is the parent document.\n"
825 static PyTypeObject PageClass =
827 PyObject_HEAD_INIT(NULL)
830 tp_basicsize: sizeof(PageObject),
832 tp_dealloc: page_dealloc,
833 tp_print: page_print,
834 tp_getattr: page_getattr,
835 tp_setattr: page_setattr,
837 tp_methods: page_methods
839 PyDoc_STRVAR(doc_doc,
840 "A Doc object is used for storing a document (like a PDF).\n"
841 "doc.pages contains the number of pages in the document,\n"
842 "and doc.filename the name of the file the document was\n"
843 "created (loaded) from. If the document was created from\n"
844 "an image file, the number of pages is always 1\n"
846 static PyTypeObject DocClass =
848 PyObject_HEAD_INIT(NULL)
851 tp_basicsize: sizeof(DocObject),
853 tp_dealloc: doc_dealloc,
855 tp_getattr: doc_getattr,
856 tp_setattr: doc_setattr,
858 tp_methods: doc_methods,
861 //=====================================================================
863 PyDoc_STRVAR(f_setparameter_doc, \
864 "setparameter(key,value)\n\n"
865 "Set a parameter in the gfx module (which might affect the PDF\n"
866 "parser or any of the rendering backends). This is a parameter\n"
867 "which would usually be passed with the \"-s\" option to pdf2swf.\n"
868 "For a list of all parameters, see the output of\n"
871 " pdf2swf somefile.pdf -s help\n"
874 static PyObject* f_setparameter(PyObject* self, PyObject* args, PyObject* kwargs)
876 static char *kwlist[] = {"key", "value", NULL};
878 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
880 pdfdriver->set_parameter(pdfdriver,key,value);
884 PyDoc_STRVAR(f_verbose_doc, \
886 "Set the logging verbosity of the gfx module. Log levels are:\n"
887 "level=-1 Log nothing\n"
888 "level=0 (fatal) Log only fatal errors\n"
889 "level=1 (error) Log only fatal errors and errors\n"
890 "level=2 (warn) Log all errors and warnings\n"
891 "level=3 (notice) Log also some rudimentary data about the parsing/conversion\n"
892 "level=4 (verbose) Log some additional parsing information\n"
893 "level=5 (debug) Log debug statements\n"
894 "level=6 (trace) Log extended debug statements\n"
895 "All logging messages are written to stdout.\n"
897 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
899 static char *kwlist[] = {"val", NULL};
901 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
903 setConsoleLogging(val);
907 PyDoc_STRVAR(f_addfont_doc, \
908 "addfont(filename)\n\n"
909 "Passes an additional font file to the PDF parser. If a PDF contains\n"
910 "external fonts (i.e. fonts which are not contained in the PDF itself)\n"
911 "then the files added by addfont() will be searched.\n"
914 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
916 static char *kwlist[] = {"filename", NULL};
918 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
920 pdfdriver->set_parameter(pdfdriver,"font", filename);
924 PyDoc_STRVAR(f_addfontdir_doc, \
925 "addfontdir(dirname)\n\n"
926 "Passes a complete directory containing fonts to the PDF parser. Any\n"
927 "font file within this directory might be used to resolve external fonts\n"
930 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
932 static char *kwlist[] = {"filename", NULL};
934 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
936 pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
940 static PyMethodDef pdf2swf_methods[] =
943 {"open", (PyCFunction)f_open, METH_KEYWORDS, f_open_doc},
944 {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, f_addfont_doc},
945 {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, f_addfontdir_doc},
946 {"setparameter", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc},
947 {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, f_verbose_doc},
950 {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, f_createSWF_doc},
951 {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, f_createImageList_doc},
952 {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, f_createPlainText_doc},
953 {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, f_createPassThrough_doc},
959 PyDoc_STRVAR(gfx_doc, \
960 "This module contains a PDF parser (based on xpdf) and a number of\n"
961 "rendering backends. In particular, it can extract text from PDF pages,\n"
962 "create bitmaps from them, or convert PDF files to SWF.\n"
963 "The latter functionality is similar to what is offered by swftools'\n"
964 "(http://www.swftools.org) pdf2swf utility, however more powerful-\n"
965 "You can also create individual SWF files from single pages of the PDF\n"
966 "or mix pages from different PDF files.\n"
971 initLog(0,0,0,0,0,2);
972 OutputClass.ob_type = &PyType_Type;
973 PageClass.ob_type = &PyType_Type;
974 DocClass.ob_type = &PyType_Type;
976 pdfdriver = gfxsource_pdf_create();
977 swfdriver = gfxsource_swf_create();
978 imagedriver = gfxsource_image_create();
980 PyObject*module = Py_InitModule3("gfx", pdf2swf_methods, gfx_doc);
981 PyObject*module_dict = PyModule_GetDict(module);
983 PyDict_SetItemString(module_dict, "Doc", (PyObject*)&DocClass);
984 PyDict_SetItemString(module_dict, "Page", (PyObject*)&PageClass);
985 PyDict_SetItemString(module_dict, "Output", (PyObject*)&OutputClass);