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/ocr.h"
29 #include "../devices/rescale.h"
30 #include "../devices/text.h"
31 #include "../pdf/pdf.h"
32 #include "../readers/swf.h"
33 #include "../readers/image.h"
37 static gfxsource_t*pdfdriver = 0;
38 static gfxsource_t*swfdriver = 0;
39 static gfxsource_t*imagedriver = 0;
41 staticforward PyTypeObject OutputClass;
42 staticforward PyTypeObject PageClass;
43 staticforward PyTypeObject DocClass;
47 gfxdevice_t*output_device;
48 PyObject*pyobj; //only for passthrough
64 static char* strf(char*format, ...)
69 va_start(arglist, format);
70 vsprintf(buf, format, arglist);
74 #define PY_ERROR(s,args...) (PyErr_SetString(PyExc_Exception, strf(s, ## args)),NULL)
75 #define PY_NONE Py_BuildValue("s", 0)
77 //---------------------------------------------------------------------
78 PyDoc_STRVAR(output_save_doc, \
80 "Saves the contents of an output device to a file\n"
81 "Depending on what the output device is, the contents\n"
82 "of the file may be plain text, an image, an SWF file,\n"
84 "For the ImageList device, several files (named\n"
85 "filename.1.png, filename.2.png etc.) might be created)\n"
87 static PyObject* output_save(PyObject* _self, PyObject* args, PyObject* kwargs)
89 OutputObject* self = (OutputObject*)_self;
91 static char *kwlist[] = {"filename", NULL};
92 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
95 gfxresult_t*result = self->output_device->finish(self->output_device);
96 self->output_device = 0;
97 if(result->save(result, filename) < 0) {
98 return PY_ERROR("Couldn't write to %s", filename);
100 result->destroy(result);
104 PyDoc_STRVAR(output_startpage_doc, \
105 "startpage(width, height)\n\n"
106 "Starts a new page/frame in the output device.\n"
107 "The usual way to render documents is to start a new page in the\n"
108 "device for each page in the document:\n"
110 "for pagenr in range(1,doc.pages+1):\n"
111 " page = doc.getPage(pagenr)\n"
112 " output.startpage(page.width, page.height)\n"
113 " page.render(output)\n"
114 " output.endpage()\n"
116 "It is, however, also possible to render more than one document page\n"
117 "to a single output page. E.g. for side-by-side or book views.\n"
119 static PyObject* output_startpage(PyObject* _self, PyObject* args, PyObject* kwargs)
121 OutputObject* self = (OutputObject*)_self;
122 int width=0, height=0;
123 if (!PyArg_ParseTuple(args, "ii", &width, &height))
125 self->output_device->startpage(self->output_device, width, height);
128 PyDoc_STRVAR(output_endpage_doc, \
130 "Ends a page in the output device. This function should be called\n"
131 "once for every startpage()\n"
133 static PyObject* output_endpage(PyObject* _self, PyObject* args, PyObject* kwargs)
135 OutputObject* self = (OutputObject*)_self;
136 if (!PyArg_ParseTuple(args, ""))
138 self->output_device->endpage(self->output_device);
141 PyDoc_STRVAR(output_setparameter_doc, \
142 "setparameter(key, value)\n\n"
143 "Set a output-device dependent parameter"
145 static PyObject* output_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
147 OutputObject* self = (OutputObject*)_self;
148 static char *kwlist[] = {"key", "value", NULL};
150 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
152 self->output_device->setparameter(self->output_device, key, value);
155 PyDoc_STRVAR(f_createSWF_doc, \
157 "Creates a device which renders documents to SWF (Flash) files.\n"
158 "Depending on the way the document parser behaves (see the poly2bitmap\n"
159 "and bitmap parameters), the resulting SWF might use vector operations\n"
160 "and Flash Texts to display the document, or just a single bitmap.\n"
162 static PyObject* f_createSWF(PyObject* parent, PyObject* args, PyObject* kwargs)
164 static char *kwlist[] = {NULL};
165 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
167 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
169 self->output_device = malloc(sizeof(gfxdevice_t));
170 gfxdevice_swf_init(self->output_device);
171 return (PyObject*)self;
174 PyDoc_STRVAR(f_createOCR_doc, \
176 "Creates a device which processes documents using OCR (optical\n"
177 "character recognition).\n"
178 "This is handy for e.g. extracting fulltext from PDF documents\n"
179 "which have broken fonts, and where hence the \"PlainText\"\n"
180 "device doesn't work.\n"
182 static PyObject* f_createOCR(PyObject* parent, PyObject* args, PyObject* kwargs)
184 static char *kwlist[] = {NULL};
185 if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
187 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
189 self->output_device = malloc(sizeof(gfxdevice_t));
190 gfxdevice_ocr_init(self->output_device);
191 return (PyObject*)self;
195 PyDoc_STRVAR(f_createImageList_doc, \
197 "Creates a device which renders documents to bitmaps.\n"
198 "Each page that is rendered will create new bitmap.\n"
199 "Using save(), you can save the images to a number\n"
202 static PyObject* f_createImageList(PyObject* parent, PyObject* args, PyObject* kwargs)
204 static char *kwlist[] = {NULL};
205 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
207 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
209 self->output_device = malloc(sizeof(gfxdevice_t));
210 gfxdevice_render_init(self->output_device);
211 return (PyObject*)self;
214 PyDoc_STRVAR(f_createPlainText_doc, \
216 "Creates a device which can be used to extract text from documents,\n"
217 "by passing it as parameter to page.render().\n"
218 "The extracted text can be saved by plaintext.save(filename).\n"
220 static PyObject* f_createPlainText(PyObject* parent, PyObject* args, PyObject* kwargs)
222 static char *kwlist[] = {NULL};
223 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
225 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
227 self->output_device = malloc(sizeof(gfxdevice_t));
228 gfxdevice_text_init(self->output_device);
229 return (PyObject*)self;
232 static PyObject*callback_python(char*function, gfxdevice_t*dev, const char*format, ...)
234 OutputObject*self = (OutputObject*)dev->internal;
236 if(!PyObject_HasAttrString(self->pyobj, function))
240 va_start(ap, format);
242 PyObject*tuple = PyTuple_New(strlen(format));
245 char p = format[pos];
247 char*s = va_arg(ap, char*);
248 PyTuple_SetItem(tuple, pos, PyString_FromString(s));
250 int i = va_arg(ap, int);
251 PyTuple_SetItem(tuple, pos, PyInt_FromLong(i));
253 void* ptr = va_arg(ap, void*);
254 gfxcolor_t*col = (gfxcolor_t*)ptr;
255 PyObject*colobj = PyTuple_New(4);
256 PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->r));
257 PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->g));
258 PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->b));
259 PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->a));
260 PyTuple_SetItem(tuple, pos, colobj);
262 void* ptr = va_arg(ap, void*);
263 gfxline_t*line = (gfxline_t*)ptr;
267 while(l) {l=l->next;len++;}
268 PyObject*list = PyList_New(len);
272 if(l->type == gfx_moveTo) {
273 point = PyTuple_New(3);
274 PyTuple_SetItem(point, 0, PyString_FromString("m"));
275 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
276 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
277 } else if(l->type == gfx_lineTo) {
278 point = PyTuple_New(3);
279 PyTuple_SetItem(point, 0, PyString_FromString("l"));
280 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
281 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
282 } else if(l->type == gfx_splineTo) {
283 point = PyTuple_New(5);
284 PyTuple_SetItem(point, 0, PyString_FromString("s"));
285 PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
286 PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
287 PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sx));
288 PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
292 PyList_SetItem(list, i, point);
296 PyTuple_SetItem(tuple, pos, list);
298 PyTuple_SetItem(tuple, pos, PY_NONE);
303 PyObject*f = PyObject_GetAttrString(self->pyobj, function);
307 PyObject* result = PyObject_CallObject(f, tuple);
319 static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
321 callback_python("setparameter", dev, "ss", key, value);
324 static void my_startpage(gfxdevice_t*dev, int width, int height)
326 callback_python("startpage", dev, "ii", width, height);
328 static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
330 callback_python("startclip", dev, "l", line);
332 static void my_endclip(gfxdevice_t*dev)
334 callback_python("endclip", dev, "");
336 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)
340 if(cap_style == gfx_capButt)
342 else if(cap_style == gfx_capRound)
344 else if(cap_style == gfx_capSquare)
346 if(joint_style == gfx_joinMiter)
348 else if(joint_style == gfx_joinRound)
350 else if(joint_style == gfx_joinBevel)
352 callback_python("stroke", dev, "licssi", line, width, color, cap, joint, miterLimit);
354 static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
356 callback_python("fill", dev, "lc", line, color);
358 static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
360 callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
362 static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
364 callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
366 static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
368 callback_python("addfont", dev, "f", font);
370 static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
372 callback_python("drawchar", dev, "ficm", font, glyph, color, matrix);
374 static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
376 callback_python("drawlink", dev, "ls", line, action);
378 static void my_endpage(gfxdevice_t*dev)
380 callback_python("drawlink", dev, "");
382 static gfxresult_t* my_finish(gfxdevice_t*dev)
384 callback_python("finish", dev, "");
389 PyDoc_STRVAR(f_createPassThrough_doc, \
390 "PassThrough(device)\n\n"
391 "Creates a PassThrough device, which can be used as parameter in calls\n"
392 "to page.render().\n"
393 "device needs to be a class implementing at least the following functions:\n\n"
394 "setparameter(key,value)\n"
395 "startclip(outline)\n"
397 "stroke(outline, width, color, capstyle, jointstyle, miterLimit)\n"
398 "fill(outline, color)\n"
399 "fillbitmap(outline, image, matrix, colortransform)\n"
400 "fillgradient(outline, gradient, gradienttype, matrix)\n"
402 "drawchar(font, glyph, color, matrix)\n"
403 "drawlink(outline, url)\n"
404 "If any of these functions are not defined, a error message will be printed,\n"
405 "however the rendering process will *not* be aborted.\n"
407 static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
409 static char *kwlist[] = {"device", NULL};
411 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
413 OutputObject*self = PyObject_New(OutputObject, &OutputClass);
416 self->output_device = malloc(sizeof(gfxdevice_t));
417 memset(self->output_device, 0, sizeof(gfxdevice_t));
418 self->output_device->name = strdup("passthrough");
420 self->output_device->setparameter = my_setparameter;
421 self->output_device->startpage = my_startpage;
422 self->output_device->startclip = my_startclip;
423 self->output_device->addfont = my_addfont;
424 self->output_device->endclip = my_endclip;
425 self->output_device->stroke = my_stroke;
426 self->output_device->fill = my_fill;
427 self->output_device->fillbitmap = my_fillbitmap;
428 self->output_device->fillgradient = my_fillgradient;
429 self->output_device->drawchar = my_drawchar;
430 self->output_device->drawlink = my_drawlink;
431 self->output_device->endpage = my_endpage;
432 self->output_device->finish = my_finish;
433 self->output_device->internal = self;
435 return (PyObject*)self;
438 static PyMethodDef output_methods[] =
440 /* Output functions */
441 {"save", (PyCFunction)output_save, METH_KEYWORDS, output_save_doc},
442 {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, output_startpage_doc},
443 {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, output_endpage_doc},
444 {"setparameter", (PyCFunction)output_setparameter, METH_KEYWORDS, output_setparameter_doc},
448 static void output_dealloc(PyObject* _self) {
449 OutputObject* self = (OutputObject*)_self;
451 if(self->output_device) {
452 gfxresult_t*result = self->output_device->finish(self->output_device);
454 result->destroy(result);result=0;
456 self->output_device = 0;
461 static PyObject* output_getattr(PyObject * _self, char* a)
463 OutputObject*self = (OutputObject*)_self;
465 /* if(!strcmp(a, "x1")) {
466 return PyInt_FromLong(self->output_device->x1);
467 } else if(!strcmp(a, "y1")) {
468 return PyInt_FromLong(self->output_device->y1);
469 } else if(!strcmp(a, "x2")) {
470 return PyInt_FromLong(self->output_device->x2);
471 } else if(!strcmp(a, "y2")) {
472 return PyInt_FromLong(self->output_device->y2);
475 return Py_FindMethod(output_methods, _self, a);
477 static int output_setattr(PyObject * _self, char* a, PyObject * o)
479 OutputObject*self = (OutputObject*)_self;
480 if(!PyString_Check(o))
482 char*value = PyString_AsString(o);
483 self->output_device->setparameter(self->output_device, a, value);
486 static int output_print(PyObject * _self, FILE *fi, int flags)
488 OutputObject*self = (OutputObject*)_self;
489 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
493 //---------------------------------------------------------------------
494 staticforward PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs);
495 staticforward PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs);
497 PyDoc_STRVAR(page_render_doc, \
498 "render(output, move=(0,0), clip=None)\n\n"
499 "Renders a page to the rendering backend specified by the output\n"
500 "parameter. Rendering consists of calling a number of functions on the\n"
501 "output device, see the description of the \"PassThrough\" device.\n"
502 "The page may be shifted to a given position using the move parameter,\n"
503 "and may also be clipped to a specific size using the clip parameter.\n"
504 "The clipping operation is applied after the move operation.\n"
506 static PyObject* page_render(PyObject* _self, PyObject* args, PyObject* kwargs)
508 PageObject* self = (PageObject*)_self;
510 static char *kwlist[] = {"dev", "move", "clip", NULL};
511 OutputObject*output = 0;
514 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &OutputClass, &output,
520 int cx1=0,cy1=0,cx2=0,cy2=0;
523 if (!PyArg_ParseTuple(move, "ii", &x,&y))
527 if (!PyArg_ParseTuple(clip, "iiii", &cx1,&cy1,&cx2,&cy2))
531 if(x|y|cx1|cx2|cy1|cy2)
532 self->page->rendersection(self->page, output->output_device,x,y,cx1,cy1,cx2,cy2);
534 self->page->render(self->page, output->output_device);
538 PyDoc_STRVAR(page_asImage_doc, \
539 "asImage(width, height)\n\n"
540 "Creates a bitmap from a page. The bitmap will be returned as a string\n"
541 "containing RGB triplets. The bitmap will be rescaled to the specified width and\n"
542 "height. The aspect ratio of width and height doesn't need to be the same\n"
545 static PyObject* page_asImage(PyObject* _self, PyObject* args, PyObject* kwargs)
547 PageObject* self = (PageObject*)_self;
549 static char *kwlist[] = {"width", "height", NULL};
550 int width=0,height=0;
551 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &width, &height))
554 if(!width || !height) {
555 return PY_ERROR("invalid dimensions: %dx%d", width,height);
558 gfxdevice_t dev1,dev2;
559 gfxdevice_render_init(&dev1);
560 dev1.setparameter(&dev1, "antialise", "2");
561 gfxdevice_rescale_init(&dev2, &dev1, width, height, 0);
562 dev2.startpage(&dev2, self->page->width, self->page->height);
563 self->page->render(self->page, &dev2);
565 gfxresult_t*result = dev2.finish(&dev2);
566 gfximage_t*img = (gfximage_t*)result->get(result,"page0");
567 int l = img->width*img->height;
568 unsigned char*data = malloc(img->width*img->height*3);
570 for(t=0,s=0;t<l;s+=3,t++) {
571 data[s+0] = img->data[t].r;
572 data[s+1] = img->data[t].g;
573 data[s+2] = img->data[t].b;
575 result->destroy(result);
576 return PyString_FromStringAndSize((char*)data,img->width*img->height*3);
579 static PyMethodDef page_methods[] =
582 {"render", (PyCFunction)page_render, METH_KEYWORDS, page_render_doc},
583 {"asImage", (PyCFunction)page_asImage, METH_KEYWORDS, page_asImage_doc},
586 static void page_dealloc(PyObject* _self) {
587 PageObject* self = (PageObject*)_self;
589 self->page->destroy(self->page);
593 Py_DECREF(self->parent);
600 static PyObject* page_getattr(PyObject * _self, char* a)
602 PageObject*self = (PageObject*)_self;
604 if(!strcmp(a, "size")) {
605 return Py_BuildValue("(ii)", self->page->width, self->page->height);
606 } if(!strcmp(a, "doc")) {
607 Py_INCREF(self->parent);
609 } if(!strcmp(a, "nr")) {
610 return PyInt_FromLong(self->nr);
611 } else if(!strcmp(a, "width")) {
612 return PyInt_FromLong(self->page->width);
613 } else if(!strcmp(a, "height")) {
614 return PyInt_FromLong(self->page->height);
616 return Py_FindMethod(page_methods, _self, a);
619 static int page_setattr(PyObject * self, char* a, PyObject * o) {
622 static int page_print(PyObject * _self, FILE *fi, int flags)
624 PageObject*self = (PageObject*)_self;
625 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
629 //---------------------------------------------------------------------
631 PyDoc_STRVAR(doc_getPage_doc,
633 "Get one page from a document file. The nr parameter specifies\n"
634 "which page to retrieve. Counting starts at 1, so the first page\n"
635 "can be retrieved by\n"
636 " page = doc.getPage(1)\n"
638 "You can find out how many pages a document contains by querying\n"
639 "its pages field (doc.pages)\n"
641 static PyObject* doc_getPage(PyObject* _self, PyObject* args, PyObject* kwargs)
643 DocObject* self = (DocObject*)_self;
645 static char *kwlist[] = {"nr", NULL};
647 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &pagenr))
650 PageObject*page = PyObject_New(PageObject, &PageClass);
651 page->page = self->doc->getpage(self->doc, pagenr);
653 page->parent = _self;
654 Py_INCREF(page->parent);
657 return PY_ERROR("Couldn't extract page %d", pagenr);
659 return (PyObject*)page;
662 PyDoc_STRVAR(doc_getInfo_doc,
664 "Retrieve some information about a document. For PDF files, key\n"
665 "can have the following values:\n\n"
666 "\"title\", \"subject\", \"keywords\", \"author\", \"creator\", \"producer\",\n"
667 "\"creationdate\", \"moddate\", \"linearized\", \"tagged\", \"encrypted\",\n"
668 "\"oktoprint\", \"oktocopy\", \"oktochange\", \"oktoaddnotes\", \"version\".\n\n"
669 "If the \"oktocopy\" digital rights management flag is set to \"no\", then the\n"
670 "pdf parser won't allow you to access the PDF file. Trying to extract pages\n"
671 "from it will raise an exception.\n"
673 static PyObject* doc_getInfo(PyObject* _self, PyObject* args, PyObject* kwargs)
675 DocObject* self = (DocObject*)_self;
677 static char *kwlist[] = {"key", NULL};
679 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &key))
682 char*s = self->doc->getinfo(self->doc, key);
683 return PyString_FromString(s);
686 PyDoc_STRVAR(doc_setparameter_doc,
687 "setparameter(key, value)\n\n"
688 "Pass a parameter or setting to the document parser. Unlike\n"
689 "the module level setparameter() function, the parameters set\n"
690 "using setparameter will only be valid for the object itself\n"
691 "during its lifetime.\n"
693 static PyObject* doc_setparameter(PyObject* _self, PyObject* args, PyObject* kwargs)
695 DocObject* self = (DocObject*)_self;
697 static char *kwlist[] = {"key", "value", NULL};
698 char*key = 0, *value=0;
699 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key,&value))
702 self->doc->set_parameter(self->doc, key, value);
706 PyDoc_STRVAR(f_open_doc,
707 "open(type, filename) -> object\n\n"
708 "Open a PDF, SWF or image file. The type argument should be \"pdf\",\n"
709 "\"swf\" or \"image\" accordingly. It returns a doc object which can be\n"
710 "used to process the file contents.\n"
712 " doc = open(\"pdf\", \"document.pdf\")\n"
713 " doc = open(\"swf\", \"flashfile.swf\")\n"
714 " doc = open(\"image\", \"image.png\")\n"
715 "If the file could not be loaded, or is a encrypted PDF file without\n"
716 "a proper password specified, an exception is being raised.\n"
717 "If the filename argument contains a '|' char, everything behind\n"
718 "the '|' is treated as password used for opening the file.\n"
720 " doc = open(\"pdf\", \"document.pdf|mysecretpassword\")\n"
722 "Notice that for image files, the only supported file formats right now\n"
723 "are jpeg and png.\n"
725 static PyObject* f_open(PyObject* parent, PyObject* args, PyObject* kwargs)
727 static char *kwlist[] = {"type", "filename", NULL};
730 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &type, &filename)) {
731 static char *kwlist2[] = {"filename", NULL};
734 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist2, &filename))
738 DocObject*self = PyObject_New(DocObject, &DocClass);
740 if(!type) { //autodetect
741 type = "pdf"; //default
742 int l = strlen(filename);
744 if(filename[l-4]=='.') {
745 if(strchr("pP", filename[l-3]) && strchr("dD", filename[l-2]) && strchr("fF", filename[l-1]))
747 if(strchr("jJ", filename[l-3]) && strchr("pP", filename[l-2]) && strchr("gG", filename[l-1]))
749 if(strchr("pP", filename[l-3]) && strchr("nN", filename[l-2]) && strchr("gG", filename[l-1]))
751 if(strchr("sS", filename[l-3]) && strchr("wW", filename[l-2]) && strchr("fF", filename[l-1]))
753 } else if(filename[l-5]=='.') {
759 if(!strcmp(type,"pdf"))
760 self->doc = pdfdriver->open(pdfdriver,filename);
761 else if(!strcmp(type, "image") || !strcmp(type, "img"))
762 self->doc = imagedriver->open(imagedriver, filename);
763 else if(!strcmp(type, "swf") || !strcmp(type, "SWF"))
764 self->doc = swfdriver->open(imagedriver, filename);
766 return PY_ERROR("Unknown type %s", type);
770 return PY_ERROR("Couldn't open %s", filename);
772 self->filename = strdup(filename);
773 return (PyObject*)self;
776 static PyMethodDef doc_methods[] =
779 {"getPage", (PyCFunction)doc_getPage, METH_KEYWORDS, doc_getPage_doc},
780 {"getInfo", (PyCFunction)doc_getInfo, METH_KEYWORDS, doc_getInfo_doc},
781 {"setparameter", (PyCFunction)doc_setparameter, METH_KEYWORDS, doc_setparameter_doc},
785 static void doc_dealloc(PyObject* _self) {
786 DocObject* self = (DocObject*)_self;
788 self->doc->destroy(self->doc);
792 free(self->filename);self->filename=0;
796 static PyObject* doc_getattr(PyObject * _self, char* a)
798 DocObject*self = (DocObject*)_self;
799 if(!strcmp(a, "pages")) {
800 return PyInt_FromLong(self->doc->num_pages);
802 if(!strcmp(a, "filename")) {
803 return PyString_FromString(self->filename);
805 return Py_FindMethod(doc_methods, _self, a);
807 static int doc_setattr(PyObject * self, char* a, PyObject * o) {
810 static int doc_print(PyObject * _self, FILE *fi, int flags)
812 DocObject*self = (DocObject*)_self;
813 fprintf(fi, "%08x(%d)", (int)_self, _self?_self->ob_refcnt:0);
817 //---------------------------------------------------------------------
819 PyDoc_STRVAR(output_doc,
820 "An Output object can be used as parameter to the render()\n"
821 "call of a page. It's not possible to create this type of\n"
822 "object directly (i.e., from a class), however you can\n"
823 "use a PassThrough() device to pass things over to Python.\n"
824 "Examples for classes implementing the Output class are: \n"
825 "ImageList, SWF, PlainText and PassThrough.\n"
827 static PyTypeObject OutputClass =
829 PyObject_HEAD_INIT(NULL)
831 tp_name: "gfx.Output",
832 tp_basicsize: sizeof(OutputObject),
834 tp_dealloc: output_dealloc,
835 tp_print: output_print,
836 tp_getattr: output_getattr,
837 tp_setattr: output_setattr,
839 tp_methods: output_methods
841 PyDoc_STRVAR(page_doc,
842 "A Page object contains a single page of a document.\n"
843 "page.width and page.height (or page.size) contain the\n"
844 "page dimensions. page.nr is the number of the page, and\n"
845 "page.doc is the parent document.\n"
847 static PyTypeObject PageClass =
849 PyObject_HEAD_INIT(NULL)
852 tp_basicsize: sizeof(PageObject),
854 tp_dealloc: page_dealloc,
855 tp_print: page_print,
856 tp_getattr: page_getattr,
857 tp_setattr: page_setattr,
859 tp_methods: page_methods
861 PyDoc_STRVAR(doc_doc,
862 "A Doc object is used for storing a document (like a PDF).\n"
863 "doc.pages contains the number of pages in the document,\n"
864 "and doc.filename the name of the file the document was\n"
865 "created (loaded) from. If the document was created from\n"
866 "an image file, the number of pages is always 1\n"
868 static PyTypeObject DocClass =
870 PyObject_HEAD_INIT(NULL)
873 tp_basicsize: sizeof(DocObject),
875 tp_dealloc: doc_dealloc,
877 tp_getattr: doc_getattr,
878 tp_setattr: doc_setattr,
880 tp_methods: doc_methods,
883 //=====================================================================
885 PyDoc_STRVAR(f_setparameter_doc, \
886 "setparameter(key,value)\n\n"
887 "Set a parameter in the gfx module (which might affect the PDF\n"
888 "parser or any of the rendering backends). This is a parameter\n"
889 "which would usually be passed with the \"-s\" option to pdf2swf.\n"
890 "For a list of all parameters, see the output of\n"
893 " pdf2swf somefile.pdf -s help\n"
896 static PyObject* f_setparameter(PyObject* self, PyObject* args, PyObject* kwargs)
898 static char *kwlist[] = {"key", "value", NULL};
900 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, &key, &value))
902 pdfdriver->set_parameter(pdfdriver,key,value);
906 PyDoc_STRVAR(f_verbose_doc, \
908 "Set the logging verbosity of the gfx module. Log levels are:\n"
909 "level=-1 Log nothing\n"
910 "level=0 (fatal) Log only fatal errors\n"
911 "level=1 (error) Log only fatal errors and errors\n"
912 "level=2 (warn) Log all errors and warnings\n"
913 "level=3 (notice) Log also some rudimentary data about the parsing/conversion\n"
914 "level=4 (verbose) Log some additional parsing information\n"
915 "level=5 (debug) Log debug statements\n"
916 "level=6 (trace) Log extended debug statements\n"
917 "All logging messages are written to stdout.\n"
919 static PyObject* f_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
921 static char *kwlist[] = {"val", NULL};
923 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &val))
925 setConsoleLogging(val);
929 PyDoc_STRVAR(f_addfont_doc, \
930 "addfont(filename)\n\n"
931 "Passes an additional font file to the PDF parser. If a PDF contains\n"
932 "external fonts (i.e. fonts which are not contained in the PDF itself)\n"
933 "then the files added by addfont() will be searched.\n"
936 static PyObject* f_addfont(PyObject* self, PyObject* args, PyObject* kwargs)
938 static char *kwlist[] = {"filename", NULL};
940 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
942 pdfdriver->set_parameter(pdfdriver,"font", filename);
946 PyDoc_STRVAR(f_addfontdir_doc, \
947 "addfontdir(dirname)\n\n"
948 "Passes a complete directory containing fonts to the PDF parser. Any\n"
949 "font file within this directory might be used to resolve external fonts\n"
952 static PyObject* f_addfontdir(PyObject* self, PyObject* args, PyObject* kwargs)
954 static char *kwlist[] = {"filename", NULL};
956 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
958 pdfdriver->set_parameter(pdfdriver,"fontdir", filename);
962 static PyMethodDef pdf2swf_methods[] =
965 {"open", (PyCFunction)f_open, METH_KEYWORDS, f_open_doc},
966 {"addfont", (PyCFunction)f_addfont, METH_KEYWORDS, f_addfont_doc},
967 {"addfontdir", (PyCFunction)f_addfontdir, METH_KEYWORDS, f_addfontdir_doc},
968 {"setparameter", (PyCFunction)f_setparameter, METH_KEYWORDS, f_setparameter_doc},
969 {"verbose", (PyCFunction)f_verbose, METH_KEYWORDS, f_verbose_doc},
972 {"SWF", (PyCFunction)f_createSWF, METH_KEYWORDS, f_createSWF_doc},
973 {"OCR", (PyCFunction)f_createOCR, METH_KEYWORDS, f_createOCR_doc},
974 {"ImageList", (PyCFunction)f_createImageList, METH_KEYWORDS, f_createImageList_doc},
975 {"PlainText", (PyCFunction)f_createPlainText, METH_KEYWORDS, f_createPlainText_doc},
976 {"PassThrough", (PyCFunction)f_createPassThrough, METH_KEYWORDS, f_createPassThrough_doc},
982 PyDoc_STRVAR(gfx_doc, \
983 "This module contains a PDF parser (based on xpdf) and a number of\n"
984 "rendering backends. In particular, it can extract text from PDF pages,\n"
985 "create bitmaps from them, or convert PDF files to SWF.\n"
986 "The latter functionality is similar to what is offered by swftools'\n"
987 "(http://www.swftools.org) pdf2swf utility, however more powerful-\n"
988 "You can also create individual SWF files from single pages of the PDF\n"
989 "or mix pages from different PDF files.\n"
994 initLog(0,0,0,0,0,2);
995 OutputClass.ob_type = &PyType_Type;
996 PageClass.ob_type = &PyType_Type;
997 DocClass.ob_type = &PyType_Type;
999 pdfdriver = gfxsource_pdf_create();
1000 swfdriver = gfxsource_swf_create();
1001 imagedriver = gfxsource_image_create();
1003 PyObject*module = Py_InitModule3("gfx", pdf2swf_methods, gfx_doc);
1004 PyObject*module_dict = PyModule_GetDict(module);
1006 PyDict_SetItemString(module_dict, "Doc", (PyObject*)&DocClass);
1007 PyDict_SetItemString(module_dict, "Page", (PyObject*)&PageClass);
1008 PyDict_SetItemString(module_dict, "Output", (PyObject*)&OutputClass);