mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add DrawingWand to ImageMagick API
This commit is contained in:
parent
34d427dfd5
commit
07d3e42cda
@ -7,14 +7,41 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from calibre.constants import plugins
|
from calibre.constants import plugins, filesystem_encoding
|
||||||
|
|
||||||
_magick, _merr = plugins['magick']
|
_magick, _merr = plugins['magick']
|
||||||
|
|
||||||
if _magick is None:
|
if _magick is None:
|
||||||
raise RuntimeError('Failed to load ImageMagick: '+_merr)
|
raise RuntimeError('Failed to load ImageMagick: '+_merr)
|
||||||
|
|
||||||
class Image(_magick.Image):
|
_gravity_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if
|
||||||
|
x.endswith('Gravity')])
|
||||||
|
|
||||||
|
class DrawingWand(_magick.DrawingWand): # {{{
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def font(self):
|
||||||
|
def fget(self):
|
||||||
|
return self.font_.decode(filesystem_encoding, 'replace').lower()
|
||||||
|
def fset(self, val):
|
||||||
|
if isinstance(val, unicode):
|
||||||
|
val = val.encode(filesystem_encoding)
|
||||||
|
self.font_ = str(val)
|
||||||
|
return property(fget=fget, fset=fset, doc=_magick.DrawingWand.font_.__doc__)
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def gravity(self):
|
||||||
|
def fget(self):
|
||||||
|
val = self.gravity_
|
||||||
|
return _gravity_map[val]
|
||||||
|
def fset(self, val):
|
||||||
|
val = getattr(_magick, str(val))
|
||||||
|
self.gravity_ = val
|
||||||
|
return property(fget=fget, fset=fset, doc=_magick.DrawingWand.gravity_.__doc__)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class Image(_magick.Image): # {{{
|
||||||
|
|
||||||
def load(self, data):
|
def load(self, data):
|
||||||
return _magick.Image.load(self, bytes(data))
|
return _magick.Image.load(self, bytes(data))
|
||||||
@ -70,6 +97,8 @@ class Image(_magick.Image):
|
|||||||
raise ValueError('left and/or top out of bounds')
|
raise ValueError('left and/or top out of bounds')
|
||||||
_magick.Image.compose(self, img, int(left), int(top), op)
|
_magick.Image.compose(self, img, int(left), int(top), op)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
def create_canvas(width, height, bgcolor):
|
def create_canvas(width, height, bgcolor):
|
||||||
canvas = Image()
|
canvas = Image()
|
||||||
canvas.create_canvas(int(width), int(height), str(bgcolor))
|
canvas.create_canvas(int(width), int(height), str(bgcolor))
|
||||||
|
@ -49,7 +49,7 @@ def get_value(const):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
constants = []
|
constants = []
|
||||||
for x in ('resample', 'image', 'draw', 'distort', 'composite'):
|
for x in ('resample', 'image', 'draw', 'distort', 'composite', 'geometry'):
|
||||||
constants += list(parse_enums('magick/%s.h'%x))
|
constants += list(parse_enums('magick/%s.h'%x))
|
||||||
base = os.path.dirname(__file__)
|
base = os.path.dirname(__file__)
|
||||||
constants = [
|
constants = [
|
||||||
|
@ -16,6 +16,220 @@ PyObject* magick_set_exception(MagickWand *wand) {
|
|||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// DrawingWand object definition {{{
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
// Type-specific fields go here.
|
||||||
|
DrawingWand *wand;
|
||||||
|
|
||||||
|
} magick_DrawingWand;
|
||||||
|
|
||||||
|
static void
|
||||||
|
magick_DrawingWand_dealloc(magick_DrawingWand* self)
|
||||||
|
{
|
||||||
|
if (self->wand != NULL) self->wand = DestroyDrawingWand(self->wand);
|
||||||
|
self->ob_type->tp_free((PyObject*)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_DrawingWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
magick_DrawingWand *self;
|
||||||
|
|
||||||
|
self = (magick_DrawingWand *)type->tp_alloc(type, 0);
|
||||||
|
if (self != NULL) {
|
||||||
|
self->wand = NewDrawingWand();
|
||||||
|
if (self->wand == NULL || self->wand < 0) {
|
||||||
|
PyErr_SetString(PyExc_Exception, "Failed to allocate wand.");
|
||||||
|
self->wand = NULL;
|
||||||
|
Py_DECREF(self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawingWand.font {{{
|
||||||
|
static PyObject *
|
||||||
|
magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
const char *fp;
|
||||||
|
fp = DrawGetFont(self->wand);
|
||||||
|
return Py_BuildValue("s", fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
|
char *fmt;
|
||||||
|
|
||||||
|
if (val == NULL) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand font");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = PyString_AsString(val);
|
||||||
|
if (fmt == NULL) return -1;
|
||||||
|
|
||||||
|
if (!DrawSetFont(self->wand, fmt)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Unknown font");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// DrawingWand.font_size {{{
|
||||||
|
static PyObject *
|
||||||
|
magick_DrawingWand_fontsize_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
return Py_BuildValue("d", DrawGetFontSize(self->wand));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
|
if (val == NULL) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand fontsize");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyFloat_Check(val)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Font size must be a float");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawSetFontSize(self->wand, PyFloat_AsDouble(val));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// DrawingWand.text_antialias {{{
|
||||||
|
static PyObject *
|
||||||
|
magick_DrawingWand_textantialias_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
return PyBool_FromLong((long)DrawGetTextAntialias(self->wand));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
|
if (val == NULL) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand textantialias");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
DrawSetTextAntialias(self->wand, (MagickBooleanType)PyObject_IsTrue(val));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// DrawingWand.gravity {{{
|
||||||
|
static PyObject *
|
||||||
|
magick_DrawingWand_gravity_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
return Py_BuildValue("n", DrawGetGravity(self->wand));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
|
GravityType grav;
|
||||||
|
|
||||||
|
if (val == NULL) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand gravity");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyInt_Check(val)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Gravity must be an integer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
grav = PyInt_AsSsize_t(val);
|
||||||
|
|
||||||
|
DrawSetGravity(self->wand, grav);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
|
||||||
|
// DrawingWand attr list {{{
|
||||||
|
static PyMethodDef magick_DrawingWand_methods[] = {
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyGetSetDef magick_DrawingWand_getsetters[] = {
|
||||||
|
{(char *)"font_",
|
||||||
|
(getter)magick_DrawingWand_font_getter, (setter)magick_DrawingWand_font_setter,
|
||||||
|
(char *)"DrawingWand font path. Absolute path to font file.",
|
||||||
|
NULL},
|
||||||
|
|
||||||
|
{(char *)"font_size",
|
||||||
|
(getter)magick_DrawingWand_fontsize_getter, (setter)magick_DrawingWand_fontsize_setter,
|
||||||
|
(char *)"DrawingWand fontsize",
|
||||||
|
NULL},
|
||||||
|
|
||||||
|
{(char *)"text_antialias",
|
||||||
|
(getter)magick_DrawingWand_textantialias_getter, (setter)magick_DrawingWand_textantialias_setter,
|
||||||
|
(char *)"DrawingWand text antialias",
|
||||||
|
NULL},
|
||||||
|
|
||||||
|
{(char *)"gravity_",
|
||||||
|
(getter)magick_DrawingWand_gravity_getter, (setter)magick_DrawingWand_gravity_setter,
|
||||||
|
(char *)"DrawingWand gravity",
|
||||||
|
NULL},
|
||||||
|
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
static PyTypeObject magick_DrawingWandType = { // {{{
|
||||||
|
PyObject_HEAD_INIT(NULL)
|
||||||
|
0, /*ob_size*/
|
||||||
|
"magick.DrawingWand", /*tp_name*/
|
||||||
|
sizeof(magick_DrawingWand), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
(destructor)magick_DrawingWand_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*/
|
||||||
|
"DrawingWand", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
magick_DrawingWand_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
magick_DrawingWand_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_DrawingWand_new, /* tp_new */
|
||||||
|
}; // }}}
|
||||||
|
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Image object definition {{{
|
// Image object definition {{{
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
@ -44,7 +258,7 @@ magick_Image_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||||||
if (self != NULL) {
|
if (self != NULL) {
|
||||||
self->wand = NewMagickWand();
|
self->wand = NewMagickWand();
|
||||||
if (self->wand == NULL || self->wand < 0) {
|
if (self->wand == NULL || self->wand < 0) {
|
||||||
PyErr_SetString(PyExc_Exception, "Failed to allocate wand. Did you initialize ImageMgick?");
|
PyErr_SetString(PyExc_Exception, "Failed to allocate wand.");
|
||||||
self->wand = NULL;
|
self->wand = NULL;
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -140,8 +354,8 @@ magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) {
|
|||||||
MagickBooleanType res;
|
MagickBooleanType res;
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
return -1;
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete image size");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete image size");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PySequence_Check(val) || PySequence_Length(val) < 4) {
|
if (!PySequence_Check(val) || PySequence_Length(val) < 4) {
|
||||||
@ -189,8 +403,8 @@ magick_Image_format_setter(magick_Image *self, PyObject *val, void *closure) {
|
|||||||
char *fmt;
|
char *fmt;
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
return -1;
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete image format");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete image format");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt = PyString_AsString(val);
|
fmt = PyString_AsString(val);
|
||||||
@ -361,12 +575,16 @@ initmagick(void)
|
|||||||
|
|
||||||
if (PyType_Ready(&magick_ImageType) < 0)
|
if (PyType_Ready(&magick_ImageType) < 0)
|
||||||
return;
|
return;
|
||||||
|
if (PyType_Ready(&magick_DrawingWandType) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
m = Py_InitModule3("magick", magick_methods,
|
m = Py_InitModule3("magick", magick_methods,
|
||||||
"Wrapper for the ImageMagick imaging library");
|
"Wrapper for the ImageMagick imaging library");
|
||||||
|
|
||||||
Py_INCREF(&magick_ImageType);
|
Py_INCREF(&magick_ImageType);
|
||||||
PyModule_AddObject(m, "Image", (PyObject *)&magick_ImageType);
|
PyModule_AddObject(m, "Image", (PyObject *)&magick_ImageType);
|
||||||
|
Py_INCREF(&magick_DrawingWandType);
|
||||||
|
PyModule_AddObject(m, "DrawingWand", (PyObject *)&magick_DrawingWandType);
|
||||||
|
|
||||||
magick_add_module_constants(m);
|
magick_add_module_constants(m);
|
||||||
MagickWandGenesis();
|
MagickWandGenesis();
|
||||||
|
@ -226,4 +226,41 @@ static void magick_add_module_constants(PyObject *m) {
|
|||||||
PyModule_AddIntConstant(m, "LinearDodgeCompositeOp", 61);
|
PyModule_AddIntConstant(m, "LinearDodgeCompositeOp", 61);
|
||||||
PyModule_AddIntConstant(m, "LinearBurnCompositeOp", 62);
|
PyModule_AddIntConstant(m, "LinearBurnCompositeOp", 62);
|
||||||
PyModule_AddIntConstant(m, "MathematicsCompositeOp", 63);
|
PyModule_AddIntConstant(m, "MathematicsCompositeOp", 63);
|
||||||
|
PyModule_AddIntConstant(m, "NoValue", 0);
|
||||||
|
PyModule_AddIntConstant(m, "XValue", 1);
|
||||||
|
PyModule_AddIntConstant(m, "XiValue", 1);
|
||||||
|
PyModule_AddIntConstant(m, "YValue", 2);
|
||||||
|
PyModule_AddIntConstant(m, "PsiValue", 2);
|
||||||
|
PyModule_AddIntConstant(m, "WidthValue", 4);
|
||||||
|
PyModule_AddIntConstant(m, "RhoValue", 4);
|
||||||
|
PyModule_AddIntConstant(m, "HeightValue", 8);
|
||||||
|
PyModule_AddIntConstant(m, "SigmaValue", 8);
|
||||||
|
PyModule_AddIntConstant(m, "ChiValue", 16);
|
||||||
|
PyModule_AddIntConstant(m, "XiNegative", 32);
|
||||||
|
PyModule_AddIntConstant(m, "XNegative", 32);
|
||||||
|
PyModule_AddIntConstant(m, "PsiNegative", 64);
|
||||||
|
PyModule_AddIntConstant(m, "YNegative", 64);
|
||||||
|
PyModule_AddIntConstant(m, "ChiNegative", 128);
|
||||||
|
PyModule_AddIntConstant(m, "PercentValue", 4096);
|
||||||
|
PyModule_AddIntConstant(m, "AspectValue", 8192);
|
||||||
|
PyModule_AddIntConstant(m, "NormalizeValue", 8192);
|
||||||
|
PyModule_AddIntConstant(m, "LessValue", 16384);
|
||||||
|
PyModule_AddIntConstant(m, "GreaterValue", 32768);
|
||||||
|
PyModule_AddIntConstant(m, "MinimumValue", 65536);
|
||||||
|
PyModule_AddIntConstant(m, "CorrelateNormalizeValue", 65536);
|
||||||
|
PyModule_AddIntConstant(m, "AreaValue", 131072);
|
||||||
|
PyModule_AddIntConstant(m, "DecimalValue", 262144);
|
||||||
|
PyModule_AddIntConstant(m, "AllValues", 2147483647);
|
||||||
|
PyModule_AddIntConstant(m, "UndefinedGravity", 0);
|
||||||
|
PyModule_AddIntConstant(m, "ForgetGravity", 0);
|
||||||
|
PyModule_AddIntConstant(m, "NorthWestGravity", 1);
|
||||||
|
PyModule_AddIntConstant(m, "NorthGravity", 2);
|
||||||
|
PyModule_AddIntConstant(m, "NorthEastGravity", 3);
|
||||||
|
PyModule_AddIntConstant(m, "WestGravity", 4);
|
||||||
|
PyModule_AddIntConstant(m, "CenterGravity", 5);
|
||||||
|
PyModule_AddIntConstant(m, "EastGravity", 6);
|
||||||
|
PyModule_AddIntConstant(m, "SouthWestGravity", 7);
|
||||||
|
PyModule_AddIntConstant(m, "SouthGravity", 8);
|
||||||
|
PyModule_AddIntConstant(m, "SouthEastGravity", 9);
|
||||||
|
PyModule_AddIntConstant(m, "StaticGravity", 10);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user