From e4ab5891aaa6489d2f507dc6a62ea1058d9e7a8c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Aug 2010 20:00:59 -0600 Subject: [PATCH] Initial C based implementation of ImageMagick plugin --- setup/extensions.py | 7 + src/calibre/constants.py | 1 + src/calibre/utils/magick/__init__.py | 85 +++++++ src/calibre/utils/magick/generate.py | 70 +++++ src/calibre/utils/magick/magick.c | 269 ++++++++++++++++++++ src/calibre/utils/magick/magick_constants.h | 165 ++++++++++++ src/calibre/utils/podofo/podofo.cpp | 2 +- 7 files changed, 598 insertions(+), 1 deletion(-) create mode 100644 src/calibre/utils/magick/__init__.py create mode 100644 src/calibre/utils/magick/generate.py create mode 100644 src/calibre/utils/magick/magick.c create mode 100644 src/calibre/utils/magick/magick_constants.h diff --git a/setup/extensions.py b/setup/extensions.py index 5251737101..df6f0ffbcd 100644 --- a/setup/extensions.py +++ b/setup/extensions.py @@ -72,6 +72,13 @@ extensions = [ lib_dirs=chmlib_lib_dirs, cflags=["-D__PYTHON__"]), + Extension('magick', + ['calibre/utils/magick/magick.c'], + headers=['calibre/utils/magick/magick_constants.h'], + libraries=magick_libs, + lib_dirs=magick_lib_dirs, + inc_dirs=magick_inc_dirs + ), Extension('pdfreflow', reflow_sources, diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 0af364910c..23936f2280 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -60,6 +60,7 @@ if plugins is None: 'pictureflow', 'lzx', 'msdes', + 'magick', 'podofo', 'cPalmdoc', 'fontconfig', diff --git a/src/calibre/utils/magick/__init__.py b/src/calibre/utils/magick/__init__.py new file mode 100644 index 0000000000..fdd1af333a --- /dev/null +++ b/src/calibre/utils/magick/__init__.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +import os + +from calibre.constants import plugins + +_magick, _merr = plugins['magick'] + +if _magick is None: + raise RuntimeError('Failed to load ImageMagick: '+_merr) + +# class ImageMagick {{{ +_initialized = False +def initialize(): + global _initialized + if not _initialized: + _magick.genesis() + _initialized = True + +def finalize(): + global _initialized + if _initialized: + _magick.terminus() + _initialized = False + +class ImageMagick(object): + + def __enter__(self): + initialize() + + def __exit__(self, *args): + finalize() +# }}} + +class Image(_magick.Image): + + def open(self, path_or_file): + data = path_or_file + if hasattr(data, 'read'): + data = data.read() + else: + data = open(data, 'rb').read() + self.load(data) + + @dynamic_property + def format(self): + def fget(self): + ans = super(Image, self).format + return ans.decode('utf-8', 'ignore').lower() + def fset(self, val): + super(Image, self).format = str(val) + return property(fget=fget, fset=fset, doc=_magick.Image.format.__doc__) + + + @dynamic_property + def size(self): + def fget(self): + return super(Image, self).size + def fset(self, val): + filter = 'CatromFilter' + if len(val) > 2: + filter = val[2] + filter = int(getattr(_magick, filter)) + blur = 1.0 + if len(val) > 3: + blur = float(val[3]) + super(Image, self).format = (int(val[0]), int(val[1]), filter, + blur) + return property(fget=fget, fset=fset, doc=_magick.Image.size.__doc__) + + + def save(self, path, format=None): + if format is None: + ext = os.path.splitext(path)[1] + if len(ext) < 2: + raise ValueError('No format specified') + format = ext[1:] + + with open(path, 'wb') as f: + f.write(self.export(format)) diff --git a/src/calibre/utils/magick/generate.py b/src/calibre/utils/magick/generate.py new file mode 100644 index 0000000000..bb5fe177ff --- /dev/null +++ b/src/calibre/utils/magick/generate.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +import os, textwrap, re, subprocess + +INC = '/usr/include/ImageMagick' + +''' +Various constants defined in the ImageMagick header files. Note that +they are defined as actual numeric constants rather than symbolic names to +ensure that the extension can be compiled against older versions of ImageMagick +than the one this script is run against. +''' + +def parse_enums(f): + print '\nParsing:', f + raw = open(os.path.join(INC, f)).read() + raw = re.sub(r'(?s)/\*.*?\*/', '', raw) + raw = re.sub('#.*', '', raw) + + for enum in re.findall(r'typedef\s+enum\s+\{([^}]+)', raw): + enum = re.sub(r'(?s)/\*.*?\*/', '', enum) + for x in enum.splitlines(): + e = x.split(',')[0].strip().split(' ')[0] + if e: + val = get_value(e) + print e, val + yield e, val + +def get_value(const): + t = ''' + #include + #include + int main(int argc, char **argv) { + printf("%%d", %s); + return 0; + } + '''%const + with open('/tmp/ig.c','wb') as f: + f.write(t) + subprocess.check_call(['gcc', '-I/usr/include/ImageMagick', '/tmp/ig.c', '-o', '/tmp/ig', '-lMagickWand']) + return int(subprocess.Popen(["/tmp/ig"], + stdout=subprocess.PIPE).communicate()[0].strip()) + + +def main(): + constants = [] + for x in ('resample', 'image', 'draw', 'distort'): + constants += list(parse_enums('magick/%s.h'%x)) + base = os.path.dirname(__file__) + constants = [ + 'PyModule_AddIntConstant(m, "{0}", {1});'.format(c, v) for c, v in + constants] + raw = textwrap.dedent('''\ + // Generated by generate.py + + static void magick_add_module_constants(PyObject *m) { + %s + } + ''')%'\n '.join(constants) + with open(os.path.join(base, 'magick_constants.h'), 'wb') as f: + f.write(raw) + + +if __name__ == '__main__': + main() diff --git a/src/calibre/utils/magick/magick.c b/src/calibre/utils/magick/magick.c new file mode 100644 index 0000000000..cf1c4c3872 --- /dev/null +++ b/src/calibre/utils/magick/magick.c @@ -0,0 +1,269 @@ +#define UNICODE +#define PY_SSIZE_T_CLEAN +#include +#include + +#include "magick_constants.h" + +PyObject* magick_set_exception(MagickWand *wand) { + ExceptionType ext; + char *desc = MagickGetException(wand, &ext); + PyErr_SetString(PyExc_Exception, desc); + MagickClearException(wand); + desc = MagickRelinquishMemory(desc); + return NULL; +} + +// Image object definition {{{ +typedef struct { + PyObject_HEAD + // Type-specific fields go here. + MagickWand *wand; + +} magick_Image; + +static void +magick_Image_dealloc(magick_Image* self) +{ + if (self->wand != NULL) self->wand = DestroyMagickWand(self->wand); + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject * +magick_Image_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + magick_Image *self; + + self = (magick_Image *)type->tp_alloc(type, 0); + if (self != NULL) { + self->wand = NewMagickWand(); + if (self->wand == NULL || self->wand < 0) { + PyErr_SetString(PyExc_Exception, "Failed to allocate wand. Did you initialize ImageMgick?"); + self->wand = NULL; + Py_DECREF(self); + return NULL; + } + } + + return (PyObject *)self; +} + +static PyObject * +magick_Image_load(magick_Image *self, PyObject *args, PyObject *kwargs) { + const char *data; + Py_ssize_t dlen; + + if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL; + + if (!MagickReadImageBlob(self->wand, data, dlen)) + return magick_set_exception(self->wand); + + Py_RETURN_NONE; +} + +static PyObject * +magick_Image_export(magick_Image *self, PyObject *args, PyObject *kwargs) { + char *fmt; + unsigned char *data; + PyObject *ans; + size_t len = 0; + + if (!PyArg_ParseTuple(args, "s", &fmt)) return NULL; + + if (!MagickSetFormat(self->wand, fmt)) { + PyErr_SetString(PyExc_ValueError, "Unknown image format"); + return NULL; + } + + data = MagickGetImageBlob(self->wand, &len); + if (data == NULL || len < 1) + return magick_set_exception(self->wand); + + ans = Py_BuildValue("s#", data, len); + data = MagickRelinquishMemory(data); + + return ans; +} + + + +static PyObject * +magick_Image_size_getter(magick_Image *self, void *closure) { + size_t width, height; + width = MagickGetImageWidth(self->wand); + height = MagickGetImageHeight(self->wand); + return Py_BuildValue("II", width, height); +} + +static int +magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) { + Py_ssize_t width, height; + FilterTypes filter; + double blur; + + if (val == NULL) { + return -1; + PyErr_SetString(PyExc_TypeError, "Cannot delete image size"); + } + + if (!PySequence_Check(val) || PySequence_Length(val) < 4) { + PyErr_SetString(PyExc_TypeError, "Must use at least a 4 element sequence to set size"); + return -1; + } + + width = PyInt_AsSsize_t(PySequence_ITEM(val, 0)); + height = PyInt_AsSsize_t(PySequence_ITEM(val, 1)); + filter = (FilterTypes)PyInt_AsSsize_t(PySequence_ITEM(val, 2)); + blur = PyFloat_AsDouble(PySequence_ITEM(val, 2)); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Width, height, filter or blur not a number"); + return -1; + } + + if ( filter <= UndefinedFilter || filter >= SentinelFilter) { + PyErr_SetString(PyExc_ValueError, "Invalid filter"); + return -1; + } + + if (!MagickResizeImage(self->wand, width, height, filter, blur)) { + magick_set_exception(self->wand); + return -1; + } + + return 0; + +} + + +static PyObject * +magick_Image_format_getter(magick_Image *self, void *closure) { + const char *fmt; + fmt = MagickGetImageFormat(self->wand); + return Py_BuildValue("s", fmt); +} + + +static PyMethodDef magick_Image_methods[] = { + {"load", (PyCFunction)magick_Image_load, METH_VARARGS, + "Load an image from a byte buffer (string)" + }, + + {"export", (PyCFunction)magick_Image_export, METH_VARARGS, + "export(format) -> bytestring\n\n Export the image as the specified format" + }, + + {NULL} /* Sentinel */ +}; + +static PyGetSetDef magick_Image_getsetters[] = { + {(char *)"size", + (getter)magick_Image_size_getter, (setter)magick_Image_size_setter, + (char *)"Image size (width, height). When setting pass in (width, height, filter, blur). See MagickResizeImage docs.", + NULL}, + + {(char *)"format", + (getter)magick_Image_format_getter, NULL, + (char *)"Image format", + NULL}, + + {NULL} /* Sentinel */ +}; + +static PyTypeObject magick_ImageType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "magick.Image", /*tp_name*/ + sizeof(magick_Image), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)magick_Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "Images", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + magick_Image_methods, /* tp_methods */ + 0, /* tp_members */ + magick_Image_getsetters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + magick_Image_new, /* tp_new */ +}; + + + +// }}} + +// Module functions {{{ + +static PyObject * +magick_genesis(PyObject *self, PyObject *args) +{ + MagickWandGenesis(); + Py_RETURN_NONE; +} + +static PyObject * +magick_terminus(PyObject *self, PyObject *args) +{ + MagickWandTerminus(); + Py_RETURN_NONE; +} + +static PyMethodDef magick_methods[] = { + {"genesis", magick_genesis, METH_VARARGS, + "genesis()\n\n" + "Initializes ImageMagick.\n" + "Must be called before any other use of this module is made. " + }, + + {"terminus", magick_terminus, METH_VARARGS, + "terminus()\n\n" + "Cleans up ImageMagick memory structures.\n" + "Must be called after you are done using this module. You can call genesis() again after this to resume using the module." + }, + + {NULL} /* Sentinel */ +}; +// }}} + +// Module initialization {{{ +PyMODINIT_FUNC +initmagick(void) +{ + PyObject* m; + + if (PyType_Ready(&magick_ImageType) < 0) + return; + + m = Py_InitModule3("magick", magick_methods, + "Wrapper for the ImageMagick imaging library"); + + Py_INCREF(&magick_ImageType); + PyModule_AddObject(m, "Image", (PyObject *)&magick_ImageType); + + magick_add_module_constants(m); +} +// }}} diff --git a/src/calibre/utils/magick/magick_constants.h b/src/calibre/utils/magick/magick_constants.h new file mode 100644 index 0000000000..060a0017d9 --- /dev/null +++ b/src/calibre/utils/magick/magick_constants.h @@ -0,0 +1,165 @@ +// Generated by generate.py + +static void magick_add_module_constants(PyObject *m) { + PyModule_AddIntConstant(m, "UndefinedFilter", 0); + PyModule_AddIntConstant(m, "PointFilter", 1); + PyModule_AddIntConstant(m, "BoxFilter", 2); + PyModule_AddIntConstant(m, "TriangleFilter", 3); + PyModule_AddIntConstant(m, "HermiteFilter", 4); + PyModule_AddIntConstant(m, "HanningFilter", 5); + PyModule_AddIntConstant(m, "HammingFilter", 6); + PyModule_AddIntConstant(m, "BlackmanFilter", 7); + PyModule_AddIntConstant(m, "GaussianFilter", 8); + PyModule_AddIntConstant(m, "QuadraticFilter", 9); + PyModule_AddIntConstant(m, "CubicFilter", 10); + PyModule_AddIntConstant(m, "CatromFilter", 11); + PyModule_AddIntConstant(m, "MitchellFilter", 12); + PyModule_AddIntConstant(m, "LanczosFilter", 13); + PyModule_AddIntConstant(m, "BesselFilter", 14); + PyModule_AddIntConstant(m, "SincFilter", 15); + PyModule_AddIntConstant(m, "KaiserFilter", 16); + PyModule_AddIntConstant(m, "WelshFilter", 17); + PyModule_AddIntConstant(m, "ParzenFilter", 18); + PyModule_AddIntConstant(m, "LagrangeFilter", 19); + PyModule_AddIntConstant(m, "BohmanFilter", 20); + PyModule_AddIntConstant(m, "BartlettFilter", 21); + PyModule_AddIntConstant(m, "SentinelFilter", 22); + PyModule_AddIntConstant(m, "UndefinedInterpolatePixel", 0); + PyModule_AddIntConstant(m, "AverageInterpolatePixel", 1); + PyModule_AddIntConstant(m, "BicubicInterpolatePixel", 2); + PyModule_AddIntConstant(m, "BilinearInterpolatePixel", 3); + PyModule_AddIntConstant(m, "FilterInterpolatePixel", 4); + PyModule_AddIntConstant(m, "IntegerInterpolatePixel", 5); + PyModule_AddIntConstant(m, "MeshInterpolatePixel", 6); + PyModule_AddIntConstant(m, "NearestNeighborInterpolatePixel", 7); + PyModule_AddIntConstant(m, "SplineInterpolatePixel", 8); + PyModule_AddIntConstant(m, "UndefinedAlphaChannel", 0); + PyModule_AddIntConstant(m, "ActivateAlphaChannel", 1); + PyModule_AddIntConstant(m, "BackgroundAlphaChannel", 2); + PyModule_AddIntConstant(m, "CopyAlphaChannel", 3); + PyModule_AddIntConstant(m, "DeactivateAlphaChannel", 4); + PyModule_AddIntConstant(m, "ExtractAlphaChannel", 5); + PyModule_AddIntConstant(m, "OpaqueAlphaChannel", 6); + PyModule_AddIntConstant(m, "ResetAlphaChannel", 7); + PyModule_AddIntConstant(m, "SetAlphaChannel", 8); + PyModule_AddIntConstant(m, "ShapeAlphaChannel", 9); + PyModule_AddIntConstant(m, "TransparentAlphaChannel", 10); + PyModule_AddIntConstant(m, "UndefinedType", 0); + PyModule_AddIntConstant(m, "BilevelType", 1); + PyModule_AddIntConstant(m, "GrayscaleType", 2); + PyModule_AddIntConstant(m, "GrayscaleMatteType", 3); + PyModule_AddIntConstant(m, "PaletteType", 4); + PyModule_AddIntConstant(m, "PaletteMatteType", 5); + PyModule_AddIntConstant(m, "TrueColorType", 6); + PyModule_AddIntConstant(m, "TrueColorMatteType", 7); + PyModule_AddIntConstant(m, "ColorSeparationType", 8); + PyModule_AddIntConstant(m, "ColorSeparationMatteType", 9); + PyModule_AddIntConstant(m, "OptimizeType", 10); + PyModule_AddIntConstant(m, "PaletteBilevelMatteType", 11); + PyModule_AddIntConstant(m, "UndefinedInterlace", 0); + PyModule_AddIntConstant(m, "NoInterlace", 1); + PyModule_AddIntConstant(m, "LineInterlace", 2); + PyModule_AddIntConstant(m, "PlaneInterlace", 3); + PyModule_AddIntConstant(m, "PartitionInterlace", 4); + PyModule_AddIntConstant(m, "GIFInterlace", 5); + PyModule_AddIntConstant(m, "JPEGInterlace", 6); + PyModule_AddIntConstant(m, "PNGInterlace", 7); + PyModule_AddIntConstant(m, "UndefinedOrientation", 0); + PyModule_AddIntConstant(m, "TopLeftOrientation", 1); + PyModule_AddIntConstant(m, "TopRightOrientation", 2); + PyModule_AddIntConstant(m, "BottomRightOrientation", 3); + PyModule_AddIntConstant(m, "BottomLeftOrientation", 4); + PyModule_AddIntConstant(m, "LeftTopOrientation", 5); + PyModule_AddIntConstant(m, "RightTopOrientation", 6); + PyModule_AddIntConstant(m, "RightBottomOrientation", 7); + PyModule_AddIntConstant(m, "LeftBottomOrientation", 8); + PyModule_AddIntConstant(m, "UndefinedResolution", 0); + PyModule_AddIntConstant(m, "PixelsPerInchResolution", 1); + PyModule_AddIntConstant(m, "PixelsPerCentimeterResolution", 2); + PyModule_AddIntConstant(m, "UndefinedTransmitType", 0); + PyModule_AddIntConstant(m, "FileTransmitType", 1); + PyModule_AddIntConstant(m, "BlobTransmitType", 2); + PyModule_AddIntConstant(m, "StreamTransmitType", 3); + PyModule_AddIntConstant(m, "ImageTransmitType", 4); + PyModule_AddIntConstant(m, "UndefinedAlign", 0); + PyModule_AddIntConstant(m, "LeftAlign", 1); + PyModule_AddIntConstant(m, "CenterAlign", 2); + PyModule_AddIntConstant(m, "RightAlign", 3); + PyModule_AddIntConstant(m, "UndefinedPathUnits", 0); + PyModule_AddIntConstant(m, "UserSpace", 1); + PyModule_AddIntConstant(m, "UserSpaceOnUse", 2); + PyModule_AddIntConstant(m, "ObjectBoundingBox", 3); + PyModule_AddIntConstant(m, "UndefinedDecoration", 0); + PyModule_AddIntConstant(m, "NoDecoration", 1); + PyModule_AddIntConstant(m, "UnderlineDecoration", 2); + PyModule_AddIntConstant(m, "OverlineDecoration", 3); + PyModule_AddIntConstant(m, "LineThroughDecoration", 4); + PyModule_AddIntConstant(m, "UndefinedDirection", 0); + PyModule_AddIntConstant(m, "RightToLeftDirection", 1); + PyModule_AddIntConstant(m, "LeftToRightDirection", 2); + PyModule_AddIntConstant(m, "UndefinedRule", 0); + PyModule_AddIntConstant(m, "EvenOddRule", 1); + PyModule_AddIntConstant(m, "NonZeroRule", 2); + PyModule_AddIntConstant(m, "UndefinedGradient", 0); + PyModule_AddIntConstant(m, "LinearGradient", 1); + PyModule_AddIntConstant(m, "RadialGradient", 2); + PyModule_AddIntConstant(m, "UndefinedCap", 0); + PyModule_AddIntConstant(m, "ButtCap", 1); + PyModule_AddIntConstant(m, "RoundCap", 2); + PyModule_AddIntConstant(m, "SquareCap", 3); + PyModule_AddIntConstant(m, "UndefinedJoin", 0); + PyModule_AddIntConstant(m, "MiterJoin", 1); + PyModule_AddIntConstant(m, "RoundJoin", 2); + PyModule_AddIntConstant(m, "BevelJoin", 3); + PyModule_AddIntConstant(m, "UndefinedMethod", 0); + PyModule_AddIntConstant(m, "PointMethod", 1); + PyModule_AddIntConstant(m, "ReplaceMethod", 2); + PyModule_AddIntConstant(m, "FloodfillMethod", 3); + PyModule_AddIntConstant(m, "FillToBorderMethod", 4); + PyModule_AddIntConstant(m, "ResetMethod", 5); + PyModule_AddIntConstant(m, "UndefinedPrimitive", 0); + PyModule_AddIntConstant(m, "PointPrimitive", 1); + PyModule_AddIntConstant(m, "LinePrimitive", 2); + PyModule_AddIntConstant(m, "RectanglePrimitive", 3); + PyModule_AddIntConstant(m, "RoundRectanglePrimitive", 4); + PyModule_AddIntConstant(m, "ArcPrimitive", 5); + PyModule_AddIntConstant(m, "EllipsePrimitive", 6); + PyModule_AddIntConstant(m, "CirclePrimitive", 7); + PyModule_AddIntConstant(m, "PolylinePrimitive", 8); + PyModule_AddIntConstant(m, "PolygonPrimitive", 9); + PyModule_AddIntConstant(m, "BezierPrimitive", 10); + PyModule_AddIntConstant(m, "ColorPrimitive", 11); + PyModule_AddIntConstant(m, "MattePrimitive", 12); + PyModule_AddIntConstant(m, "TextPrimitive", 13); + PyModule_AddIntConstant(m, "ImagePrimitive", 14); + PyModule_AddIntConstant(m, "PathPrimitive", 15); + PyModule_AddIntConstant(m, "UndefinedReference", 0); + PyModule_AddIntConstant(m, "GradientReference", 1); + PyModule_AddIntConstant(m, "UndefinedSpread", 0); + PyModule_AddIntConstant(m, "PadSpread", 1); + PyModule_AddIntConstant(m, "ReflectSpread", 2); + PyModule_AddIntConstant(m, "RepeatSpread", 3); + PyModule_AddIntConstant(m, "UndefinedDistortion", 0); + PyModule_AddIntConstant(m, "AffineDistortion", 1); + PyModule_AddIntConstant(m, "AffineProjectionDistortion", 2); + PyModule_AddIntConstant(m, "ScaleRotateTranslateDistortion", 3); + PyModule_AddIntConstant(m, "PerspectiveDistortion", 4); + PyModule_AddIntConstant(m, "PerspectiveProjectionDistortion", 5); + PyModule_AddIntConstant(m, "BilinearForwardDistortion", 6); + PyModule_AddIntConstant(m, "BilinearDistortion", 6); + PyModule_AddIntConstant(m, "BilinearReverseDistortion", 7); + PyModule_AddIntConstant(m, "PolynomialDistortion", 8); + PyModule_AddIntConstant(m, "ArcDistortion", 9); + PyModule_AddIntConstant(m, "PolarDistortion", 10); + PyModule_AddIntConstant(m, "DePolarDistortion", 11); + PyModule_AddIntConstant(m, "BarrelDistortion", 12); + PyModule_AddIntConstant(m, "BarrelInverseDistortion", 13); + PyModule_AddIntConstant(m, "ShepardsDistortion", 14); + PyModule_AddIntConstant(m, "SentinelDistortion", 15); + PyModule_AddIntConstant(m, "UndefinedColorInterpolate", 0); + PyModule_AddIntConstant(m, "BarycentricColorInterpolate", 1); + PyModule_AddIntConstant(m, "BilinearColorInterpolate", 7); + PyModule_AddIntConstant(m, "PolynomialColorInterpolate", 8); + PyModule_AddIntConstant(m, "ShepardsColorInterpolate", 14); + PyModule_AddIntConstant(m, "VoronoiColorInterpolate", 15); +} diff --git a/src/calibre/utils/podofo/podofo.cpp b/src/calibre/utils/podofo/podofo.cpp index ea982167d3..c1f9f84f61 100644 --- a/src/calibre/utils/podofo/podofo.cpp +++ b/src/calibre/utils/podofo/podofo.cpp @@ -421,7 +421,7 @@ initpodofo(void) return; m = Py_InitModule3("podofo", podofo_methods, - "Wrapper for the PoDoFo pDF library"); + "Wrapper for the PoDoFo PDF library"); Py_INCREF(&podofo_PDFDocType); PyModule_AddObject(m, "PDFDoc", (PyObject *)&podofo_PDFDocType);