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
|
||||
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): # {{{
|
||||
|
||||
@dynamic_property
|
||||
@ -39,6 +79,14 @@ class DrawingWand(_magick.DrawingWand): # {{{
|
||||
self.gravity_ = val
|
||||
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): # {{{
|
||||
@ -97,6 +145,22 @@ class Image(_magick.Image): # {{{
|
||||
raise ValueError('left and/or top out of bounds')
|
||||
_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):
|
||||
|
@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__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):
|
||||
'''
|
||||
@ -43,4 +43,38 @@ def identify(path):
|
||||
data = open(path, 'rb').read()
|
||||
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.",
|
||||
NULL},
|
||||
|
||||
{(char *)"font_size",
|
||||
{(char *)"font_size_",
|
||||
(getter)magick_DrawingWand_fontsize_getter, (setter)magick_DrawingWand_fontsize_setter,
|
||||
(char *)"DrawingWand fontsize",
|
||||
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 {{{
|
||||
|
||||
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 {{{
|
||||
static PyMethodDef magick_Image_methods[] = {
|
||||
{"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)"
|
||||
},
|
||||
|
||||
{"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 */
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user