+
+PyDoc_STRVAR(f_createOCR_doc, \
+"OCR()\n\n"
+"Creates a device which processes documents using OCR (optical\n"
+"character recognition).\n"
+"This is handy for e.g. extracting fulltext from PDF documents\n"
+"which have broken fonts, and where hence the \"PlainText\"\n"
+"device doesn't work.\n"
+);
+static PyObject* f_createOCR(PyObject* parent, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {NULL};
+ if (args && !PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
+ return NULL;
+ OutputObject*self = PyObject_New(OutputObject, &OutputClass);
+
+ self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
+ gfxdevice_ocr_init(self->output_device);
+ return (PyObject*)self;
+}
+
+
+PyDoc_STRVAR(f_createImageList_doc, \
+"ImageList()\n\n"
+"Creates a device which renders documents to bitmaps.\n"
+"Each page that is rendered will create new bitmap.\n"
+"Using save(), you can save the images to a number\n"
+"of files\n"
+);
+static PyObject* f_createImageList(PyObject* parent, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
+ return NULL;
+ OutputObject*self = PyObject_New(OutputObject, &OutputClass);
+
+ self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
+ gfxdevice_render_init(self->output_device);
+ return (PyObject*)self;
+}
+
+PyDoc_STRVAR(f_createPlainText_doc, \
+"PlainText()\n\n"
+"Creates a device which can be used to extract text from documents,\n"
+"by passing it as parameter to page.render().\n"
+"The extracted text can be saved by plaintext.save(filename).\n"
+);
+static PyObject* f_createPlainText(PyObject* parent, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
+ return NULL;
+ OutputObject*self = PyObject_New(OutputObject, &OutputClass);
+
+ self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
+ gfxdevice_text_init(self->output_device);
+ return (PyObject*)self;
+}
+
+#ifdef USE_OPENGL
+PyDoc_STRVAR(f_createOpenGL_doc, \
+"OpenGL()\n\n"
+"Creates a device which renders everything to OpenGL.\n"
+"Can be used for desktop display and debugging.\n"
+"This device is not available on all systems.\n"
+);
+static PyObject* f_createOpenGL(PyObject* parent, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
+ return NULL;
+ OutputObject*self = PyObject_New(OutputObject, &OutputClass);
+
+ self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
+ gfxdevice_opengl_init(self->output_device);
+ return (PyObject*)self;
+}
+#endif
+
+static char callback_python(char*function, gfxdevice_t*dev, const char*format, ...)
+{
+ OutputObject*self = (OutputObject*)dev->internal;
+
+ if(!PyObject_HasAttrString(self->pyobj, function))
+ return 0;
+
+ va_list ap;
+ va_start(ap, format);
+
+ PyObject*tuple = PyTuple_New(strlen(format));
+ int pos = 0;
+ while(format[pos]) {
+ char p = format[pos];
+ if(p=='s') {
+ char*s = va_arg(ap, char*);
+ PyTuple_SetItem(tuple, pos, PyString_FromString(s));
+ } else if(p=='i') {
+ int i = va_arg(ap, int);
+ PyTuple_SetItem(tuple, pos, PyInt_FromLong(i));
+ } else if(p=='d') {
+ int i = va_arg(ap, double);
+ PyTuple_SetItem(tuple, pos, PyFloat_FromDouble(i));
+ } else if(p=='c') {
+ void* ptr = va_arg(ap, void*);
+ gfxcolor_t*col = (gfxcolor_t*)ptr;
+ PyObject*colobj = PyTuple_New(4);
+ PyTuple_SetItem(colobj, 0, PyInt_FromLong(col->a));
+ PyTuple_SetItem(colobj, 1, PyInt_FromLong(col->r));
+ PyTuple_SetItem(colobj, 2, PyInt_FromLong(col->g));
+ PyTuple_SetItem(colobj, 3, PyInt_FromLong(col->b));
+ PyTuple_SetItem(tuple, pos, colobj);
+ } else if(p=='l') {
+ void* ptr = va_arg(ap, void*);
+ gfxline_t*line = (gfxline_t*)ptr;
+ gfxline_t*l;
+ int len = 0, i = 0;
+ l = line;
+ while(l) {l=l->next;len++;}
+ PyObject*list = PyList_New(len);
+ l = line;
+ while(l) {
+ PyObject*point=0;
+ if(l->type == gfx_moveTo) {
+ point = PyTuple_New(3);
+ PyTuple_SetItem(point, 0, PyString_FromString("m"));
+ PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
+ PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
+ } else if(l->type == gfx_lineTo) {
+ point = PyTuple_New(3);
+ PyTuple_SetItem(point, 0, PyString_FromString("l"));
+ PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
+ PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
+ } else if(l->type == gfx_splineTo) {
+ point = PyTuple_New(5);
+ PyTuple_SetItem(point, 0, PyString_FromString("s"));
+ PyTuple_SetItem(point, 1, PyFloat_FromDouble(l->x));
+ PyTuple_SetItem(point, 2, PyFloat_FromDouble(l->y));
+ PyTuple_SetItem(point, 3, PyFloat_FromDouble(l->sx));
+ PyTuple_SetItem(point, 4, PyFloat_FromDouble(l->sy));
+ } else {
+ point = PY_NONE;
+ }
+ PyList_SetItem(list, i, point);
+ l = l->next;
+ i++;
+ }
+ PyTuple_SetItem(tuple, pos, list);
+ } else {
+ PyTuple_SetItem(tuple, pos, PY_NONE);
+ }
+ pos++;
+ }
+ va_end(ap);
+ PyObject*f = PyObject_GetAttrString(self->pyobj, function);
+ if(!f)
+ return 0;
+ PyErr_Clear();
+ PyObject* result = PyObject_CallObject(f, tuple);
+
+ if(!result) {
+ PyErr_Print();
+ PyErr_Clear();
+ return 1;
+ } else {
+ Py_DECREF(result);
+ return 1;
+ }
+}
+
+static int my_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+{
+ callback_python("setparameter", dev, "ss", key, value);
+ return 1;
+}
+static void my_startpage(gfxdevice_t*dev, int width, int height)
+{
+ callback_python("startpage", dev, "ii", width, height);
+}
+static void my_startclip(gfxdevice_t*dev, gfxline_t*line)
+{
+ callback_python("startclip", dev, "l", line);
+}
+static void my_endclip(gfxdevice_t*dev)
+{
+ callback_python("endclip", dev, "");
+}
+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)
+{
+ char*cap = 0;
+ char*joint = 0;
+ if(cap_style == gfx_capButt)
+ cap = "butt";
+ else if(cap_style == gfx_capRound)
+ cap = "round";
+ else if(cap_style == gfx_capSquare)
+ cap = "square";
+ if(joint_style == gfx_joinMiter)
+ joint = "miter";
+ else if(joint_style == gfx_joinRound)
+ joint = "round";
+ else if(joint_style == gfx_joinBevel)
+ joint = "bevel";
+ callback_python("stroke", dev, "ldcssi", line, width, color, cap, joint, miterLimit);
+}
+static void my_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
+{
+ callback_python("fill", dev, "lc", line, color);
+}
+static void my_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
+{
+ callback_python("fillbitmap", dev, "lImx", line, img, imgcoord2devcoord, cxform);
+}
+static void my_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
+{
+ callback_python("fillgradient", dev, "lgsm", line, gradient, type, matrix);
+}
+static void my_addfont(gfxdevice_t*dev, gfxfont_t*font)
+{
+ callback_python("addfont", dev, "f", font);
+}
+static void my_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
+{
+ if(!callback_python("drawchar", dev, "ficm", font, glyphnr, color, matrix))
+ {
+ if(!font)
+ return;
+ gfxglyph_t*glyph = &font->glyphs[glyphnr];
+ gfxline_t*line2 = gfxline_clone(glyph->line);
+ gfxline_transform(line2, matrix);
+ my_fill(dev, line2, color);
+ gfxline_free(line2);
+ return;
+ }
+}
+static void my_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
+{
+ callback_python("drawlink", dev, "ls", line, action);
+}
+static void my_endpage(gfxdevice_t*dev)
+{
+ callback_python("drawlink", dev, "");
+}
+static gfxresult_t* my_finish(gfxdevice_t*dev)
+{
+ callback_python("finish", dev, "");
+ return 0;
+}
+
+
+PyDoc_STRVAR(f_createPassThrough_doc, \
+"PassThrough(device)\n\n"
+"Creates a PassThrough device, which can be used as parameter in calls\n"
+"to page.render().\n"
+"device needs to be a class implementing at least the following functions:\n\n"
+"setparameter(key,value)\n"
+"startclip(outline)\n"
+"endclip()\n"
+"stroke(outline, width, color, capstyle, jointstyle, miterLimit)\n"
+"fill(outline, color)\n"
+"fillbitmap(outline, image, matrix, colortransform)\n"
+"fillgradient(outline, gradient, gradienttype, matrix)\n"
+"addfont(font)\n"
+"drawchar(font, glyph, color, matrix)\n"
+"drawlink(outline, url)\n"
+"If any of these functions are not defined, a error message will be printed,\n"
+"however the rendering process will *not* be aborted.\n"
+);
+static PyObject* f_createPassThrough(PyObject* parent, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {"device", NULL};
+ PyObject*obj;
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &obj))
+ return NULL;
+ OutputObject*self = PyObject_New(OutputObject, &OutputClass);
+
+ self->pyobj = obj;
+ Py_INCREF(obj);
+ self->output_device = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
+ memset(self->output_device, 0, sizeof(gfxdevice_t));
+ self->output_device->name = strdup("passthrough");
+
+ self->output_device->setparameter = my_setparameter;
+ self->output_device->startpage = my_startpage;
+ self->output_device->startclip = my_startclip;
+ self->output_device->addfont = my_addfont;
+ self->output_device->endclip = my_endclip;
+ self->output_device->stroke = my_stroke;
+ self->output_device->fill = my_fill;
+ self->output_device->fillbitmap = my_fillbitmap;
+ self->output_device->fillgradient = my_fillgradient;
+ self->output_device->drawchar = my_drawchar;
+ self->output_device->drawlink = my_drawlink;
+ self->output_device->endpage = my_endpage;
+ self->output_device->finish = my_finish;
+ self->output_device->internal = self;
+
+ return (PyObject*)self;
+}
+
+static PyMethodDef output_methods[] =
+{
+ /* Output functions */
+ {"save", (PyCFunction)output_save, METH_KEYWORDS, output_save_doc},
+ {"startpage", (PyCFunction)output_startpage, METH_KEYWORDS, output_startpage_doc},
+ {"fill", (PyCFunction)output_fill, METH_KEYWORDS, output_fill_doc},
+ {"fillbitmap", (PyCFunction)output_fillbitmap, METH_KEYWORDS, output_fillbitmap_doc},
+ {"stroke", (PyCFunction)output_stroke, METH_KEYWORDS, output_stroke_doc},
+ {"endpage", (PyCFunction)output_endpage, METH_KEYWORDS, output_endpage_doc},
+ {"setparameter", (PyCFunction)output_setparameter, METH_KEYWORDS, output_setparameter_doc},
+ {0,0,0,0}
+};
+