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"
34 gfxsource_t*pdfdriver;
36 staticforward PyTypeObject OutputClass;
37 staticforward PyTypeObject PageClass;
38 staticforward PyTypeObject DocClass;
42 gfxdevice_t*output_device;
43 PyObject*pyobj; //only for passthrough
59 static char* strf(char*format, ...)
64 va_start(arglist, format);
65 vsprintf(buf, format, arglist);
69 #define PY_ERROR(s,args...) (PyErr_SetString(PyExc_Exception, strf(s, ## args)),NULL)
70 #define PY_NONE Py_BuildValue("s", 0)
72 //---------------------------------------------------------------------
73 PyDoc_STRVAR(output_save_doc, \
75 "Saves the contents of an output device to a file\n"
76 "Depending on what the output device is, the contents\n"
77 "of the file may be plain text, an image, an SWF file,\n"
79 "For the ImageList device, several files (named\n"
80 "filename.1.png, filename.2.png etc.) might be created)\n"
82 static PyObject* output_save(PyObject* _self, PyObject* args, PyObject* kwargs)
84 OutputObject* self = (OutputObject*)_self;
86 static char *kwlist[] = {"filename", NULL};
87 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
90 gfxresult_t*result = self->output_device->finish(self->output_device);
91 self->output_device = 0;
92 if(result->save(result, filename) < 0) {
93 return PY_ERROR("Couldn't write to %s", filename);
95 result->destroy(result);
99 PyDoc_STRVAR(output_startpage_doc, \
100 "startpage(width, height)\n\n"
101 "Starts a new page/frame in the output device.\n"
102 "The usual way to render documents is to start a new page in the\n"
103 "device for each page in the document:\n"
105 "for pagenr in range(1,doc.pages+1):\n"
106 " page = doc.getPage(pagenr)\n"
107 " output.startpage(page.width, page.height)\n"
108 " page.render(output)\n"
109 " output.endpage()\n"
111 "It is, however, also possible to render more than one document page\n"
112 "to a single output page. E.g. for side-by-side or book views.\n"
114 static PyObject* output_startpage(PyObject* _self, PyObject* args, PyObject* kwargs)
116 OutputObject* self = (OutputObject*)_self;
117 int width=0, height=0;
118 if (!PyArg_ParseTuple(args, "ii", &width, &height))
120 self->output_device->startpage(self->output_device, width, height);
123 PyDoc_STRVAR(output_endpage_doc, \
125 "Ends a page in the output device. This function should be called\n"
126 "once for every startpage()\n"
128 static PyObject* output_endpage(PyObject* _self, PyObject* args, PyObject* kwargs)
130 OutputObject* self = (OutputObject*)_self;
131 if (!PyArg_ParseTuple(args, ""))
133 self->output_device->endpage(self->output_device);
136 PyDoc_STRVAR(output_setparameter_doc, \
137 "setparameter(key, value)\n\n"
138 "Set a output-device dependent parameter"
140 static PyObject* output_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
142 OutputObject* self = (OutputObject*)_self;
143 static char *kwlist[] = {"key", "value", NULL};
145 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
147 self->output_device->setparameter(self->output_device, key, value);
150 PyDoc_STRVAR(f_createSWF_doc, \
152 "Creates a device which renders documents to SWF (Flash) files.\n"
153 "Depending on the way the document parser behaves (see the poly2bitmap\n"
154 "and bitmap parameters), the resulting SWF might use vector operations\n"
155 "and Flash Texts to display the document, or just a single bitmap.\n"
157 static PyObject* f_createSWF(PyObject* parent, PyObject* args, PyObject* kwargs)
159 static char *kwlist[] = {NULL};
160 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
162 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
164 self->output_device = malloc(sizeof(gfxdevice_t));
165 gfxdevice_swf_init(self->output_device);
166 return (PyObject*)self;
169 PyDoc_STRVAR(f_createImageList_doc, \
171 "Creates a device which renders documents to bitmaps.\n"
172 "Each page that is rendered will create new bitmap.\n"
173 "Using save(), you can save the images to a number\n"
176 static PyObject* f_createImageList(PyObject* parent, PyObject* args, PyObject* kwargs)
178 static char *kwlist[] = {NULL};
179 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
181 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
183 self->output_device = malloc(sizeof(gfxdevice_t));
184 gfxdevice_render_init(self->output_device);
185 return (PyObject*)self;
188 PyDoc_STRVAR(f_createPlainText_doc, \
190 "Creates a device which can be used to extract text from documents,\n"
191 "by passing it as parameter to page.render().\n"
192 "The extracted text can be saved by plaintext.save(filename).\n"
194 static PyObject* f_createPlainText(PyObject* parent, PyObject* args, PyObject* kwargs)
196 static char *kwlist[] = {NULL};
197 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
199 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
201 self->output_device = malloc(sizeof(gfxdevice_t));
202 gfxdevice_text_init(self->output_device);
203 return (PyObject*)self;
206 static PyObject*callback_python(char*function, gfxdevice_t*dev, const char*format, ...)
208 OutputObject*self = (OutputObject*)dev->internal;
210 if(!PyObject_HasAttrString(self->pyobj, function))
214 va_start(ap, format);
216 PyObject*tuple = PyTuple_New(strlen(format));
219 char p = format[pos];
221 char*s = va_arg(ap, char*);
222 PyTuple_SetItem(tuple, pos, PyString_FromString(s));
224 int i = va_arg(ap, int);
225 PyTuple_SetItem(tuple, pos, PyInt_FromLong(i));
227 void* ptr = va_arg(ap, void*);
228 gfxcolor_t*col = (gfxcolor_t*)ptr;
229 PyObject*colobj = PyTuple_New(4);
230 PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->r));
231 PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->g));
232 PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->b));
233 PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->a));
234 PyTuple_SetItem(tuple, pos, colobj);
236 void* ptr = va_arg(ap, void*);
237 gfxline_t*line = (gfxline_t*)ptr;
241 while(l) {l=l->next;len++;}
242 PyObject*list = PyList_New(len);
246 if(l->type == gfx_moveTo) {
247 point = PyTuple_New(3);
248 PyTuple_SetItem(point, 0, PyString_FromString("m"));
249 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
250 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
251 } else if(l->type == gfx_lineTo) {
252 point = PyTuple_New(3);
253 PyTuple_SetItem(point, 0, PyString_FromString("l"));
254 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
255 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
256 } else if(l->type == gfx_splineTo) {
257 point = PyTuple_New(5);
258 PyTuple_SetItem(point, 0, PyString_FromString("s"));
259 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
260 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
261 PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sx));
262 PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
266 PyList_SetItem(list, i, point);
270 PyTuple_SetItem(tuple, pos, list);
272 PyTuple_SetItem(tuple, pos, PY_NONE);
277 PyObject*f = PyObject_GetAttrString(self->pyobj, function);
281 PyObject* result = PyObject_CallObject(f, tuple);
293 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
295 callback_python("setparameter", dev, "ss", key, value);
298 static void my_startpage(gfxdevice_t*dev, int width, int height)
300 callback_python("startpage", dev, "ii", width, height);
302 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
304 callback_python("startclip", dev, "l", line);
306 static void my_endclip(gfxdevice_t*dev)
308 callback_python("endclip", dev, "");
310 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)
314 if(cap_style == gfx_capButt)
316 else if(cap_style == gfx_capRound)
318 else if(cap_style == gfx_capSquare)
320 if(joint_style == gfx_joinMiter)
322 else if(joint_style == gfx_joinRound)
324 else if(joint_style == gfx_joinBevel)
326 callback_python("stroke", dev, "licssi", line, width, color, cap, joint, miterLimit);
328 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
330 callback_python("fill", dev, "lc", line, color);
332 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
334 callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
336 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
338 callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
340 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
342 callback_python("addfont", dev, "f", font);
344 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
346 callback_python("drawchar", dev, "ficm", font, glyph, color, matrix);
348 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
350 callback_python("drawlink", dev, "ls", line, action);
352 static void my_endpage(gfxdevice_t*dev)
354 callback_python("drawlink", dev, "");
356 static gfxresult_t* my_finish(gfxdevice_t*dev)
358 callback_python("finish", dev, "");
363 PyDoc_STRVAR(f_createPassThrough_doc, \
364 "PassThrough(device)\n\n"
365 "Creates a PassThrough device, which can be used as parameter in calls\n"
366 "to page.render().\n"
367 "device needs to be a class implementing at least the following functions:\n\n"
368 "setparameter(key,value)\n"
369 "startclip(outline)\n"
371 "stroke(outline, width, color, capstyle, jointstyle, miterLimit)\n"
372 "fill(outline, color)\n"
373 "fillbitmap(outline, image, matrix, colortransform)\n"
374 "fillgradient(outline, gradient, gradienttype, matrix)\n"
376 "drawchar(font, glyph, color, matrix)\n"
377 "drawlink(outline, url)\n"
378 "If any of these functions are not defined, a error message will be printed,\n"
379 "however the rendering process will *not* be aborted.\n"
381 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
383 static char *kwlist[] = {"device", NULL};
385 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
387 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
390 self->output_device = malloc(sizeof(gfxdevice_t));
391 memset(self->output_device, 0, sizeof(gfxdevice_t));
392 self->output_device->name = strdup("passthrough");
394 self->output_device->setparameter = my_setparameter;
395 self->output_device->startpage = my_startpage;
396 self->output_device->startclip = my_startclip;
397 self->output_device->addfont = my_addfont;
398 self->output_device->endclip = my_endclip;
399 self->output_device->stroke = my_stroke;
400 self->output_device->fill = my_fill;
401 self->output_device->fillbitmap = my_fillbitmap;
402 self->output_device->fillgradient = my_fillgradient;
403 self->output_device->drawchar = my_drawchar;
404 self->output_device->drawlink = my_drawlink;
405 self->output_device->endpage = my_endpage;
406 self->output_device->finish = my_finish;
407 self->output_device->internal = self;
409 return (PyObject*)self;
412 static PyMethodDef output_methods[] =
414 /* Output functions */
415 {"save", (PyCFunction)output_save, METH_KEYWORDS, output_save_doc},
416 {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, output_startpage_doc},
417 {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, output_endpage_doc},
418 {"setparameter", (PyCFunction)output_setparameter, METH_KEYWORDS, output_setparameter_doc},
422 static void output_dealloc(PyObject* _self) {
423 OutputObject* self = (OutputObject*)_self;
425 if(self->output_device) {
426 gfxresult_t*result = self->output_device->finish(self->output_device);
428 result->destroy(result);result=0;
430 self->output_device = 0;
435 static PyObject* output_getattr(PyObject * _self, char* a)
437 OutputObject*self = (OutputObject*)_self;
439 /* if(!strcmp(a, "x1")) {
440 return PyInt_FromLong(self->output_device->x1);
441 } else if(!strcmp(a, "y1")) {
442 return PyInt_FromLong(self->output_device->y1);
443 } else if(!strcmp(a, "x2")) {
444 return PyInt_FromLong(self->output_device->x2);
445 } else if(!strcmp(a, "y2")) {
446 return PyInt_FromLong(self->output_device->y2);
449 return Py_FindMethod(output_methods, _self, a);
451 static int output_setattr(PyObject * _self, char* a, PyObject * o)
453 OutputObject*self = (OutputObject*)_self;
454 if(!PyString_Check(o))
456 char*value = PyString_AsString(o);
457 self->output_device->setparameter(self->output_device, a, value);
460 static int output_print(PyObject * _self, FILE *fi, int flags)
462 OutputObject*self = (OutputObject*)_self;
463 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
467 //---------------------------------------------------------------------
468 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
469 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
471 PyDoc_STRVAR(page_render_doc, \
472 "render(output, move=(0,0), clip=None)\n\n"
473 "Renders a page to the rendering backend specified by the output\n"
474 "parameter. Rendering consists of calling a number of functions on the\n"
475 "output device, see the description of the \"PassThrough\" device.\n"
476 "The page may be shifted to a given position using the move parameter,\n"
477 "and may also be clipped to a specific size using the clip parameter.\n"
478 "The clipping operation is applied after the move operation.\n"
480 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
482 PageObject* self = (PageObject*)_self;
484 static char *kwlist[] = {"dev", "move", "clip", NULL};
485 OutputObject*output = 0;
488 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
494 int cx1=0,cy1=0,cx2=0,cy2=0;
497 if (!PyArg_ParseTuple(move, "ii", &x,&y))
501 if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
505 if(x|y|cx1|cx2|cy1|cy2)
506 self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
508 self->page->render(self->page, output->output_device);
512 PyDoc_STRVAR(page_asImage_doc, \
513 "asImage(width, height)\n\n"
514 "Creates a bitmap from a page. The bitmap will be returned as a string\n"
515 "containing RGB triplets. The bitmap will be rescaled to the specified width and\n"
516 "height. The aspect ratio of width and height doesn't need to be the same\n"
519 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
521 PageObject* self = (PageObject*)_self;
523 static char *kwlist[] = {"width", "height", NULL};
524 int width=0,height=0;
525 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
528 if(!width || !height) {
529 return PY_ERROR("invalid dimensions: %dx%d", width,height);
532 gfxdevice_t dev1,dev2;
533 gfxdevice_render_init(&dev1);
534 dev1.setparameter(&dev1, "antialise", "2");
535 gfxdevice_rescale_init(&dev2, &dev1, width, height, 0);
536 dev2.startpage(&dev2, self->page->width, self->page->height);
537 self->page->render(self->page, &dev2);
539 gfxresult_t*result = dev2.finish(&dev2);
540 gfximage_t*img = (gfximage_t*)result->get(result,"page0");
541 int l = img->width*img->height;
542 unsigned char*data = malloc(img->width*img->height*3);
544 for(t=0,s=0;t<l;s+=3,t++) {
545 data[s+0] = img->data[t].r;
546 data[s+1] = img->data[t].g;
547 data[s+2] = img->data[t].b;
549 result->destroy(result);
550 return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
553 static PyMethodDef page_methods[] =
556 {"render", (PyCFunction)page_render, METH_KEYWORDS, page_render_doc},
557 {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, page_asImage_doc},
560 static void page_dealloc(PyObject* _self) {
561 PageObject* self = (PageObject*)_self;
563 self->page->destroy(self->page);
567 Py_DECREF(self->parent);
574 static PyObject* page_getattr(PyObject * _self, char* a)
576 PageObject*self = (PageObject*)_self;
578 if(!strcmp(a, "size")) {
579 return Py_BuildValue("(ii)", self->page->width, self->page->height);
580 } if(!strcmp(a, "doc")) {
581 Py_INCREF(self->parent);
583 } if(!strcmp(a, "nr")) {
584 return PyInt_FromLong(self->nr);
585 } else if(!strcmp(a, "width")) {
586 return PyInt_FromLong(self->page->width);
587 } else if(!strcmp(a, "height")) {
588 return PyInt_FromLong(self->page->height);
590 return Py_FindMethod(page_methods, _self, a);
593 static int page_setattr(PyObject * self, char* a, PyObject * o) {
596 static int page_print(PyObject * _self, FILE *fi, int flags)
598 PageObject*self = (PageObject*)_self;
599 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
603 //---------------------------------------------------------------------
605 PyDoc_STRVAR(doc_getPage_doc,
607 "Get one page from a document file. The nr parameter specifies\n"
608 "which page to retrieve. Counting starts at 1, so the first page\n"
609 "can be retrieved by\n"
610 " page = doc.getPage(1)\n"
612 "You can find out how many pages a document contains by querying\n"
613 "its pages field (doc.pages)\n"
615 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
617 DocObject* self = (DocObject*)_self;
619 static char *kwlist[] = {"nr", NULL};
621 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
624 PageObject*page = PyObject_New(PageObject, &PageClass);
625 page->page = self->doc->getpage(self->doc, pagenr);
627 page->parent = _self;
628 Py_INCREF(page->parent);
631 return PY_ERROR("Couldn't extract page %d", pagenr);
633 return (PyObject*)page;
636 PyDoc_STRVAR(doc_getInfo_doc,
638 "Retrieve some information about a document. For PDF files, key\n"
639 "can have the following values:\n\n"
640 "\"title\", \"subject\", \"keywords\", \"author\", \"creator\", \"producer\",\n"
641 "\"creationdate\", \"moddate\", \"linearized\", \"tagged\", \"encrypted\",\n"
642 "\"oktoprint\", \"oktocopy\", \"oktochange\", \"oktoaddnotes\", \"version\".\n\n"
643 "If the \"oktocopy\" digital rights management flag is set to \"no\", then the\n"
644 "pdf parser won't allow you to access the PDF file. Trying to extract pages\n"
645 "from it will raise an exception.\n"
647 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
649 DocObject* self = (DocObject*)_self;
651 static char *kwlist[] = {"key", NULL};
653 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
656 char*s = self->doc->getinfo(self->doc, key);
657 return PyString_FromString(s);
660 PyDoc_STRVAR(doc_setparameter_doc,
661 "setparameter(key, value)\n\n"
662 "Pass a parameter or setting to the document parser. Unlike\n"
663 "the module level setparameter() function, the parameters set\n"
664 "using setparameter will only be valid for the object itself\n"
665 "during its lifetime.\n"
667 static PyObject* doc_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
669 DocObject* self = (DocObject*)_self;
671 static char *kwlist[] = {"key", "value", NULL};
672 char*key = 0, *value=0;
673 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
676 self->doc->set_parameter(self->doc, key, value);
680 PyDoc_STRVAR(f_open_doc,
681 "open(type, filename) -> object\n\n"
682 "Open a PDF file. The type argument always has to be \"pdf\"\n"
683 "It returns a doc object which can be used to process the pdf\n"
685 " doc = open(\"pdf\", \"document.pdf\")\n"
686 "If the file is not a PDF file or is encrypted without\n"
687 "a proper password specified, an exception is being raised.\n"
688 "If the filename argument contains a '|' char, everything behind\n"
689 "the '|' is treated as password used for opening the file.\n"
691 " doc = open(\"pdf\", \"document.pdf|mysecretpassword\")\n"
693 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
695 static char *kwlist[] = {"type", "filename", NULL};
698 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename)) {
699 static char *kwlist2[] = {"filename", NULL};
702 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist2, &filename))
706 DocObject*self = PyObject_New(DocObject, &DocClass);
708 if(!strcmp(type,"pdf"))
709 self->doc = pdfdriver->open(pdfdriver,filename);
711 return PY_ERROR("Unknown type %s", type);
715 return PY_ERROR("Couldn't open %s", filename);
717 self->filename = strdup(filename);
718 return (PyObject*)self;
721 static PyMethodDef doc_methods[] =
724 {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, doc_getPage_doc},
725 {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, doc_getInfo_doc},
726 {"setparameter", (PyCFunction)doc_setparameter, METH_KEYWORDS, doc_setparameter_doc},
730 static void doc_dealloc(PyObject* _self) {
731 DocObject* self = (DocObject*)_self;
733 self->doc->destroy(self->doc);
737 free(self->filename);self->filename=0;
741 static PyObject* doc_getattr(PyObject * _self, char* a)
743 DocObject*self = (DocObject*)_self;
744 if(!strcmp(a, "pages")) {
745 return PyInt_FromLong(self->doc->num_pages);
747 if(!strcmp(a, "filename")) {
748 return PyString_FromString(self->filename);
750 return Py_FindMethod(doc_methods, _self, a);
752 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
755 static int doc_print(PyObject * _self, FILE *fi, int flags)
757 DocObject*self = (DocObject*)_self;
758 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
762 //---------------------------------------------------------------------
764 PyDoc_STRVAR(output_doc,
765 "An Output object can be used as parameter to the render()\n"
766 "call of a page. It's not possible to create this type of\n"
767 "object directly (i.e., from a class), however you can\n"
768 "use a PassThrough() device to pass things over to Python.\n"
769 "Examples for classes implementing the Output class are: \n"
770 "ImageList, SWF, PlainText and PassThrough.\n"
772 static PyTypeObject OutputClass =
774 PyObject_HEAD_INIT(NULL)
776 tp_name: "gfx.Output",
777 tp_basicsize: sizeof(OutputObject),
779 tp_dealloc: output_dealloc,
780 tp_print: output_print,
781 tp_getattr: output_getattr,
782 tp_setattr: output_setattr,
784 tp_methods: output_methods
786 PyDoc_STRVAR(page_doc,
787 "A Page object contains a single page of a document.\n"
788 "page.width and page.height (or page.size) contain the\n"
789 "page dimensions. page.nr is the number of the page, and\n"
790 "page.doc is the parent document.\n"
792 static PyTypeObject PageClass =
794 PyObject_HEAD_INIT(NULL)
797 tp_basicsize: sizeof(PageObject),
799 tp_dealloc: page_dealloc,
800 tp_print: page_print,
801 tp_getattr: page_getattr,
802 tp_setattr: page_setattr,
804 tp_methods: page_methods
806 PyDoc_STRVAR(doc_doc,
807 "A Doc object is used for storing a document (like a PDF).\n"
808 "doc.pages contains the number of pages in the document,\n"
809 "and doc.filename the name of the file the document was\n"
810 "created (loaded) from\n"
812 static PyTypeObject DocClass =
814 PyObject_HEAD_INIT(NULL)
817 tp_basicsize: sizeof(DocObject),
819 tp_dealloc: doc_dealloc,
821 tp_getattr: doc_getattr,
822 tp_setattr: doc_setattr,
824 tp_methods: doc_methods,
827 //=====================================================================
829 PyDoc_STRVAR(f_setparameter_doc, \
830 "setparameter(key,value)\n\n"
831 "Set a parameter in the gfx module (which might affect the PDF\n"
832 "parser or any of the rendering backends). This is a parameter\n"
833 "which would usually be passed with the \"-s\" option to pdf2swf.\n"
834 "For a list of all parameters, see the output of\n"
837 " pdf2swf somefile.pdf -s help\n"
840 static PyObject* f_setparameter(PyObject* self, PyObject* args, PyObject* kwargs)
842 static char *kwlist[] = {"key", "value", NULL};
844 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
846 pdfdriver->set_parameter(pdfdriver,key,value);
850 PyDoc_STRVAR(f_verbose_doc, \
852 "Set the logging verbosity of the gfx module. Log levels are:\n"
853 "level=-1 Log nothing\n"
854 "level=0 (fatal) Log only fatal errors\n"
855 "level=1 (error) Log only fatal errors and errors\n"
856 "level=2 (warn) Log all errors and warnings\n"
857 "level=3 (notice) Log also some rudimentary data about the parsing/conversion\n"
858 "level=4 (verbose) Log some additional parsing information\n"
859 "level=5 (debug) Log debug statements\n"
860 "level=6 (trace) Log extended debug statements\n"
861 "All logging messages are written to stdout.\n"
863 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
865 static char *kwlist[] = {"val", NULL};
867 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
869 setConsoleLogging(val);
873 PyDoc_STRVAR(f_addfont_doc, \
874 "addfont(filename)\n\n"
875 "Passes an additional font file to the PDF parser. If a PDF contains\n"
876 "external fonts (i.e. fonts which are not contained in the PDF itself)\n"
877 "then the files added by addfont() will be searched.\n"
880 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
882 static char *kwlist[] = {"filename", NULL};
884 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
886 pdfdriver->set_parameter(pdfdriver,"font", filename);
890 PyDoc_STRVAR(f_addfontdir_doc, \
891 "addfontdir(dirname)\n\n"
892 "Passes a complete directory containing fonts to the PDF parser. Any\n"
893 "font file within this directory might be used to resolve external fonts\n"
896 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
898 static char *kwlist[] = {"filename", NULL};
900 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
902 pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
906 static PyMethodDef pdf2swf_methods[] =
909 {"open", (PyCFunction)f_open, METH_KEYWORDS, f_open_doc},
910 {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, f_addfont_doc},
911 {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, f_addfontdir_doc},
912 {"setoption", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc}, // for backwards-compatibility
913 {"setparameter", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc},
914 {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, f_verbose_doc},
917 {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, f_createSWF_doc},
918 {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, f_createImageList_doc},
919 {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, f_createPlainText_doc},
920 {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, f_createPassThrough_doc},
926 PyDoc_STRVAR(gfx_doc, \
927 "This module contains a PDF parser (based on xpdf) and a number of\n"
928 "rendering backends. In particular, it can extract text from PDF pages,\n"
929 "create bitmaps from them, or convert PDF files to SWF.\n"
930 "The latter functionality is similar to what is offered by swftools'\n"
931 "(http://www.swftools.org) pdf2swf utility, however more powerful-\n"
932 "You can also create individual SWF files from single pages of the PDF\n"
933 "or combine more than one page into a bigger PDF.\n"
938 initLog(0,0,0,0,0,2);
939 OutputClass.ob_type = &PyType_Type;
940 PageClass.ob_type = &PyType_Type;
941 DocClass.ob_type = &PyType_Type;
943 pdfdriver = gfxsource_pdf_create();
945 PyObject*module = Py_InitModule3("gfx", pdf2swf_methods, gfx_doc);
946 PyObject*module_dict = PyModule_GetDict(module);
948 PyDict_SetItemString(module_dict, "Doc", (PyObject*)&DocClass);
949 PyDict_SetItemString(module_dict, "Page", (PyObject*)&PageClass);
950 PyDict_SetItemString(module_dict, "Output", (PyObject*)&OutputClass);