mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
More Magick API porting
This commit is contained in:
parent
b4cd8ab9c9
commit
cb809e74a8
@ -17,6 +17,46 @@ if _magick is None:
|
|||||||
_gravity_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if
|
_gravity_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if
|
||||||
x.endswith('Gravity')])
|
x.endswith('Gravity')])
|
||||||
|
|
||||||
|
# Font metrics {{{
|
||||||
|
class Rect(object):
|
||||||
|
|
||||||
|
def __init__(self, left, top, right, bottom):
|
||||||
|
self.left, self.top, self.right, self.bottom = left, top, right, bottom
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '(%s, %s) -- (%s, %s)'%(self.left, self.top, self.right,
|
||||||
|
self.bottom)
|
||||||
|
|
||||||
|
class FontMetrics(object):
|
||||||
|
|
||||||
|
def __init__(self, ret):
|
||||||
|
self._attrs = []
|
||||||
|
for i, x in enumerate(('char_width', 'char_height', 'ascender',
|
||||||
|
'descender', 'text_width', 'text_height',
|
||||||
|
'max_horizontal_advance')):
|
||||||
|
setattr(self, x, ret[i])
|
||||||
|
self._attrs.append(x)
|
||||||
|
self.bounding_box = Rect(ret[7], ret[8], ret[9], ret[10])
|
||||||
|
self.x, self.y = ret[11], ret[12]
|
||||||
|
self._attrs.extend(['bounding_box', 'x', 'y'])
|
||||||
|
self._attrs = tuple(self._attrs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '''FontMetrics:
|
||||||
|
char_width: %s
|
||||||
|
char_height: %s
|
||||||
|
ascender: %s
|
||||||
|
descender: %s
|
||||||
|
text_width: %s
|
||||||
|
text_height: %s
|
||||||
|
max_horizontal_advance: %s
|
||||||
|
bounding_box: %s
|
||||||
|
x: %s
|
||||||
|
y: %s
|
||||||
|
'''%tuple([getattr(self, x) for x in self._attrs])
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
class DrawingWand(_magick.DrawingWand): # {{{
|
class DrawingWand(_magick.DrawingWand): # {{{
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
@ -39,6 +79,14 @@ class DrawingWand(_magick.DrawingWand): # {{{
|
|||||||
self.gravity_ = val
|
self.gravity_ = val
|
||||||
return property(fget=fget, fset=fset, doc=_magick.DrawingWand.gravity_.__doc__)
|
return property(fget=fget, fset=fset, doc=_magick.DrawingWand.gravity_.__doc__)
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def font_size(self):
|
||||||
|
def fget(self):
|
||||||
|
return self.font_size_
|
||||||
|
def fset(self, val):
|
||||||
|
self.font_size_ = float(val)
|
||||||
|
return property(fget=fget, fset=fset, doc=_magick.DrawingWand.font_size_.__doc__)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class Image(_magick.Image): # {{{
|
class Image(_magick.Image): # {{{
|
||||||
@ -97,6 +145,22 @@ 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 font_metrics(self, drawing_wand, text):
|
||||||
|
if isinstance(text, unicode):
|
||||||
|
text = text.encode('UTF-8')
|
||||||
|
return FontMetrics(_magick.Image.font_metrics(self, drawing_wand, text))
|
||||||
|
|
||||||
|
def annotate(self, drawing_wand, x, y, angle, text):
|
||||||
|
if isinstance(text, unicode):
|
||||||
|
text = text.encode('UTF-8')
|
||||||
|
return _magick.Image.annotate(self, drawing_wand, x, y, angle, text)
|
||||||
|
|
||||||
|
def distort(self, method, arguments, bestfit):
|
||||||
|
method = getattr(_magick, method)
|
||||||
|
arguments = [float(x) for x in arguments]
|
||||||
|
_magick.Image.distort(self, method, arguments, bestfit)
|
||||||
|
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def create_canvas(width, height, bgcolor):
|
def create_canvas(width, height, bgcolor):
|
||||||
|
@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
from calibre.utils.magick import Image, create_canvas
|
from calibre.utils.magick import Image, DrawingWand, create_canvas
|
||||||
|
|
||||||
def save_cover_data_to(data, path, bgcolor='white', resize_to=None):
|
def save_cover_data_to(data, path, bgcolor='white', resize_to=None):
|
||||||
'''
|
'''
|
||||||
@ -43,4 +43,38 @@ def identify(path):
|
|||||||
data = open(path, 'rb').read()
|
data = open(path, 'rb').read()
|
||||||
return identify_data(data)
|
return identify_data(data)
|
||||||
|
|
||||||
|
def add_borders_to_image(path_to_image, left=0, top=0, right=0, bottom=0,
|
||||||
|
border_color='white'):
|
||||||
|
img = Image()
|
||||||
|
img.open(path_to_image)
|
||||||
|
lwidth, lheight = img.size
|
||||||
|
canvas = create_canvas(lwidth+left+right, lheight+top+bottom,
|
||||||
|
border_color)
|
||||||
|
canvas.compose(img, left, top)
|
||||||
|
canvas.save(path_to_image)
|
||||||
|
|
||||||
|
def create_text_wand(font_size, font_path=None):
|
||||||
|
if font_path is None:
|
||||||
|
font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
|
||||||
|
ans = DrawingWand()
|
||||||
|
ans.font = font_path
|
||||||
|
ans.font_size = font_size
|
||||||
|
ans.gravity = 'CenterGravity'
|
||||||
|
ans.text_alias = True
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def create_text_arc(text, font_size, font=None, bgcolor='white'):
|
||||||
|
if isinstance(text, unicode):
|
||||||
|
text = text.encode('utf-8')
|
||||||
|
|
||||||
|
canvas = create_canvas(300, 300, bgcolor)
|
||||||
|
|
||||||
|
tw = create_text_wand(font_size, font_path=font)
|
||||||
|
m = canvas.font_metrics(tw, text)
|
||||||
|
canvas = create_canvas(int(m.text_width)+20, int(m.text_height*3.5), bgcolor)
|
||||||
|
canvas.annotate(tw, 0, 0, 0, text)
|
||||||
|
canvas.distort("ArcDistortion", [120], True)
|
||||||
|
canvas.trim(0)
|
||||||
|
return canvas
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ static PyGetSetDef magick_DrawingWand_getsetters[] = {
|
|||||||
(char *)"DrawingWand font path. Absolute path to font file.",
|
(char *)"DrawingWand font path. Absolute path to font file.",
|
||||||
NULL},
|
NULL},
|
||||||
|
|
||||||
{(char *)"font_size",
|
{(char *)"font_size_",
|
||||||
(getter)magick_DrawingWand_fontsize_getter, (setter)magick_DrawingWand_fontsize_setter,
|
(getter)magick_DrawingWand_fontsize_getter, (setter)magick_DrawingWand_fontsize_setter,
|
||||||
(char *)"DrawingWand fontsize",
|
(char *)"DrawingWand fontsize",
|
||||||
NULL},
|
NULL},
|
||||||
@ -309,6 +309,53 @@ magick_Image_create_canvas(magick_Image *self, PyObject *args, PyObject *kwargs)
|
|||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Image.font_metrics {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_Image_font_metrics(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
char *text;
|
||||||
|
PyObject *dw_, *ans, *m;
|
||||||
|
Py_ssize_t i;
|
||||||
|
DrawingWand *dw;
|
||||||
|
double *metrics;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O!s", &magick_DrawingWandType, &dw_, &text)) return NULL;
|
||||||
|
dw = ((magick_DrawingWand*)dw_)->wand;
|
||||||
|
if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; }
|
||||||
|
ans = PyTuple_New(13);
|
||||||
|
if (ans == NULL) return PyErr_NoMemory();
|
||||||
|
|
||||||
|
metrics = MagickQueryFontMetrics(self->wand, dw, text);
|
||||||
|
|
||||||
|
for (i = 0; i < 13; i++) {
|
||||||
|
m = PyFloat_FromDouble(metrics[i]);
|
||||||
|
if (m == NULL) { return PyErr_NoMemory(); }
|
||||||
|
PyTuple_SET_ITEM(ans, i, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// Image.annotate {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_Image_annotate(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
char *text;
|
||||||
|
PyObject *dw_;
|
||||||
|
DrawingWand *dw;
|
||||||
|
double x, y, angle;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O!ddds", &magick_DrawingWandType, &dw_, &x, &y, &angle, &text)) return NULL;
|
||||||
|
dw = ((magick_DrawingWand*)dw_)->wand;
|
||||||
|
if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; }
|
||||||
|
|
||||||
|
if (!MagickAnnotateImage(self->wand, dw, x, y, angle, text)) return magick_set_exception(self->wand);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Image.export {{{
|
// Image.export {{{
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
@ -420,6 +467,55 @@ magick_Image_format_setter(magick_Image *self, PyObject *val, void *closure) {
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Image.distort {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_Image_distort(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
DistortImageMethod method;
|
||||||
|
Py_ssize_t i, number;
|
||||||
|
PyObject *bestfit, *argv, *t;
|
||||||
|
MagickBooleanType res;
|
||||||
|
double *arguments = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "nOO", &method, &argv, &bestfit)) return NULL;
|
||||||
|
|
||||||
|
if (!PySequence_Check(argv)) { PyErr_SetString(PyExc_TypeError, "arguments must be a sequence"); return NULL; }
|
||||||
|
|
||||||
|
number = PySequence_Length(argv);
|
||||||
|
if (number > 0) {
|
||||||
|
arguments = (double *)PyMem_Malloc(sizeof(double) * number);
|
||||||
|
if (arguments == NULL) return PyErr_NoMemory();
|
||||||
|
for (i = 0; i < number; i++) {
|
||||||
|
t = PySequence_ITEM(argv, i);
|
||||||
|
if (t == NULL || !PyFloat_Check(t)) { PyErr_SetString(PyExc_TypeError, "Arguments must all be floats"); PyMem_Free(arguments); return NULL; }
|
||||||
|
arguments[i] = PyFloat_AsDouble(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = MagickDistortImage(self->wand, method, number, arguments, PyObject_IsTrue(bestfit));
|
||||||
|
if (arguments != NULL) PyMem_Free(arguments);
|
||||||
|
|
||||||
|
if (!res) return magick_set_exception(self->wand);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// Image.trim {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_Image_trim(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
double fuzz;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "d", &fuzz)) return NULL;
|
||||||
|
|
||||||
|
if (!MagickTrimImage(self->wand, fuzz)) return magick_set_exception(self->wand);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
|
||||||
// Image attr list {{{
|
// Image attr list {{{
|
||||||
static PyMethodDef magick_Image_methods[] = {
|
static PyMethodDef magick_Image_methods[] = {
|
||||||
{"load", (PyCFunction)magick_Image_load, METH_VARARGS,
|
{"load", (PyCFunction)magick_Image_load, METH_VARARGS,
|
||||||
@ -440,6 +536,22 @@ static PyMethodDef magick_Image_methods[] = {
|
|||||||
"compose(img, left, top, op) \n\n Compose img using operation op at (left, top)"
|
"compose(img, left, top, op) \n\n Compose img using operation op at (left, top)"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{"font_metrics", (PyCFunction)magick_Image_font_metrics, METH_VARARGS,
|
||||||
|
"font_metrics(drawing_wand, text) \n\n Return font metrics for specified drawing wand and text."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"annotate", (PyCFunction)magick_Image_annotate, METH_VARARGS,
|
||||||
|
"annotate(drawing_wand, x, y, angle, text) \n\n Annotate image with text."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"distort", (PyCFunction)magick_Image_distort, METH_VARARGS,
|
||||||
|
"distort(method, arguments, best_fit) \n\n Distort image."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"trim", (PyCFunction)magick_Image_trim, METH_VARARGS,
|
||||||
|
"trim(fuzz) \n\n Trim image."
|
||||||
|
},
|
||||||
|
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user