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 file. The type argument always has to be \"pdf\"\n"
687 "It returns a doc object which can be used to process the pdf\n"
689 " doc = open(\"pdf\", \"document.pdf\")\n"
690 "If the file is not a PDF file or is encrypted without\n"
691 "a proper password specified, an exception is being raised.\n"
692 "If the filename argument contains a '|' char, everything behind\n"
693 "the '|' is treated as password used for opening the file.\n"
695 " doc = open(\"pdf\", \"document.pdf|mysecretpassword\")\n"
697 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
699 static char *kwlist[] = {"type", "filename", NULL};
702 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename)) {
703 static char *kwlist2[] = {"filename", NULL};
706 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist2, &filename))
710 DocObject*self = PyObject_New(DocObject, &DocClass);
712 if(!type) { //autodetect
713 type = "pdf"; //default
714 int l = strlen(filename);
716 if(filename[l-4]=='.') {
717 if(strchr("pP", filename[l-3]) && strchr("dD", filename[l-2]) && strchr("fF", filename[l-1]))
719 if(strchr("jJ", filename[l-3]) && strchr("pP", filename[l-2]) && strchr("gG", filename[l-1]))
721 if(strchr("pP", filename[l-3]) && strchr("nN", filename[l-2]) && strchr("gG", filename[l-1]))
723 } else if(filename[l-5]=='.') {
729 if(!strcmp(type,"pdf"))
730 self->doc = pdfdriver->open(pdfdriver,filename);
731 else if(!strcmp(type, "image"))
732 self->doc = imagedriver->open(imagedriver, filename);
733 else if(!strcmp(type, "swf"))
734 self->doc = swfdriver->open(imagedriver, filename);
736 return PY_ERROR("Unknown type %s", type);
740 return PY_ERROR("Couldn't open %s", filename);
742 self->filename = strdup(filename);
743 return (PyObject*)self;
746 static PyMethodDef doc_methods[] =
749 {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, doc_getPage_doc},
750 {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, doc_getInfo_doc},
751 {"setparameter", (PyCFunction)doc_setparameter, METH_KEYWORDS, doc_setparameter_doc},
755 static void doc_dealloc(PyObject* _self) {
756 DocObject* self = (DocObject*)_self;
758 self->doc->destroy(self->doc);
762 free(self->filename);self->filename=0;
766 static PyObject* doc_getattr(PyObject * _self, char* a)
768 DocObject*self = (DocObject*)_self;
769 if(!strcmp(a, "pages")) {
770 return PyInt_FromLong(self->doc->num_pages);
772 if(!strcmp(a, "filename")) {
773 return PyString_FromString(self->filename);
775 return Py_FindMethod(doc_methods, _self, a);
777 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
780 static int doc_print(PyObject * _self, FILE *fi, int flags)
782 DocObject*self = (DocObject*)_self;
783 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
787 //---------------------------------------------------------------------
789 PyDoc_STRVAR(output_doc,
790 "An Output object can be used as parameter to the render()\n"
791 "call of a page. It's not possible to create this type of\n"
792 "object directly (i.e., from a class), however you can\n"
793 "use a PassThrough() device to pass things over to Python.\n"
794 "Examples for classes implementing the Output class are: \n"
795 "ImageList, SWF, PlainText and PassThrough.\n"
797 static PyTypeObject OutputClass =
799 PyObject_HEAD_INIT(NULL)
801 tp_name: "gfx.Output",
802 tp_basicsize: sizeof(OutputObject),
804 tp_dealloc: output_dealloc,
805 tp_print: output_print,
806 tp_getattr: output_getattr,
807 tp_setattr: output_setattr,
809 tp_methods: output_methods
811 PyDoc_STRVAR(page_doc,
812 "A Page object contains a single page of a document.\n"
813 "page.width and page.height (or page.size) contain the\n"
814 "page dimensions. page.nr is the number of the page, and\n"
815 "page.doc is the parent document.\n"
817 static PyTypeObject PageClass =
819 PyObject_HEAD_INIT(NULL)
822 tp_basicsize: sizeof(PageObject),
824 tp_dealloc: page_dealloc,
825 tp_print: page_print,
826 tp_getattr: page_getattr,
827 tp_setattr: page_setattr,
829 tp_methods: page_methods
831 PyDoc_STRVAR(doc_doc,
832 "A Doc object is used for storing a document (like a PDF).\n"
833 "doc.pages contains the number of pages in the document,\n"
834 "and doc.filename the name of the file the document was\n"
835 "created (loaded) from\n"
837 static PyTypeObject DocClass =
839 PyObject_HEAD_INIT(NULL)
842 tp_basicsize: sizeof(DocObject),
844 tp_dealloc: doc_dealloc,
846 tp_getattr: doc_getattr,
847 tp_setattr: doc_setattr,
849 tp_methods: doc_methods,
852 //=====================================================================
854 PyDoc_STRVAR(f_setparameter_doc, \
855 "setparameter(key,value)\n\n"
856 "Set a parameter in the gfx module (which might affect the PDF\n"
857 "parser or any of the rendering backends). This is a parameter\n"
858 "which would usually be passed with the \"-s\" option to pdf2swf.\n"
859 "For a list of all parameters, see the output of\n"
862 " pdf2swf somefile.pdf -s help\n"
865 static PyObject* f_setparameter(PyObject* self, PyObject* args, PyObject* kwargs)
867 static char *kwlist[] = {"key", "value", NULL};
869 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
871 pdfdriver->set_parameter(pdfdriver,key,value);
875 PyDoc_STRVAR(f_verbose_doc, \
877 "Set the logging verbosity of the gfx module. Log levels are:\n"
878 "level=-1 Log nothing\n"
879 "level=0 (fatal) Log only fatal errors\n"
880 "level=1 (error) Log only fatal errors and errors\n"
881 "level=2 (warn) Log all errors and warnings\n"
882 "level=3 (notice) Log also some rudimentary data about the parsing/conversion\n"
883 "level=4 (verbose) Log some additional parsing information\n"
884 "level=5 (debug) Log debug statements\n"
885 "level=6 (trace) Log extended debug statements\n"
886 "All logging messages are written to stdout.\n"
888 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
890 static char *kwlist[] = {"val", NULL};
892 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
894 setConsoleLogging(val);
898 PyDoc_STRVAR(f_addfont_doc, \
899 "addfont(filename)\n\n"
900 "Passes an additional font file to the PDF parser. If a PDF contains\n"
901 "external fonts (i.e. fonts which are not contained in the PDF itself)\n"
902 "then the files added by addfont() will be searched.\n"
905 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
907 static char *kwlist[] = {"filename", NULL};
909 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
911 pdfdriver->set_parameter(pdfdriver,"font", filename);
915 PyDoc_STRVAR(f_addfontdir_doc, \
916 "addfontdir(dirname)\n\n"
917 "Passes a complete directory containing fonts to the PDF parser. Any\n"
918 "font file within this directory might be used to resolve external fonts\n"
921 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
923 static char *kwlist[] = {"filename", NULL};
925 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
927 pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
931 static PyMethodDef pdf2swf_methods[] =
934 {"open", (PyCFunction)f_open, METH_KEYWORDS, f_open_doc},
935 {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, f_addfont_doc},
936 {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, f_addfontdir_doc},
937 {"setoption", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc}, // for backwards-compatibility
938 {"setparameter", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc},
939 {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, f_verbose_doc},
942 {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, f_createSWF_doc},
943 {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, f_createImageList_doc},
944 {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, f_createPlainText_doc},
945 {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, f_createPassThrough_doc},
951 PyDoc_STRVAR(gfx_doc, \
952 "This module contains a PDF parser (based on xpdf) and a number of\n"
953 "rendering backends. In particular, it can extract text from PDF pages,\n"
954 "create bitmaps from them, or convert PDF files to SWF.\n"
955 "The latter functionality is similar to what is offered by swftools'\n"
956 "(http://www.swftools.org) pdf2swf utility, however more powerful-\n"
957 "You can also create individual SWF files from single pages of the PDF\n"
958 "or combine more than one page into a bigger PDF.\n"
963 initLog(0,0,0,0,0,2);
964 OutputClass.ob_type = &PyType_Type;
965 PageClass.ob_type = &PyType_Type;
966 DocClass.ob_type = &PyType_Type;
968 pdfdriver = gfxsource_pdf_create();
969 swfdriver = gfxsource_swf_create();
970 imagedriver = gfxsource_image_create();
972 PyObject*module = Py_InitModule3("gfx", pdf2swf_methods, gfx_doc);
973 PyObject*module_dict = PyModule_GetDict(module);
975 PyDict_SetItemString(module_dict, "Doc", (PyObject*)&DocClass);
976 PyDict_SetItemString(module_dict, "Page", (PyObject*)&PageClass);
977 PyDict_SetItemString(module_dict, "Output", (PyObject*)&OutputClass);