mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-06 04:43:10 +03:00
fallback code
This commit is contained in:
parent
349ac49a4c
commit
326e23d3e6
|
@ -203,7 +203,8 @@ class ImageDraw(object):
|
||||||
return text.split(split_character)
|
return text.split(split_character)
|
||||||
|
|
||||||
def text(self, xy, text, fill=None, font=None, anchor=None,
|
def text(self, xy, text, fill=None, font=None, anchor=None,
|
||||||
*args, **kwargs, direction=None, features=[]):
|
*args, **kwargs, direction=None, features=None):
|
||||||
|
|
||||||
if self._multiline_check(text):
|
if self._multiline_check(text):
|
||||||
return self.multiline_text(xy, text, fill, font, anchor,
|
return self.multiline_text(xy, text, fill, font, anchor,
|
||||||
*args, **kwargs, direction=direction, features=features)
|
*args, **kwargs, direction=direction, features=features)
|
||||||
|
@ -225,7 +226,7 @@ class ImageDraw(object):
|
||||||
self.draw.draw_bitmap(xy, mask, ink)
|
self.draw.draw_bitmap(xy, mask, ink)
|
||||||
|
|
||||||
def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
|
def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
|
||||||
spacing=4, align="left", direction=None, features=[]):
|
spacing=4, align="left", direction=None, features=None):
|
||||||
widths = []
|
widths = []
|
||||||
max_width = 0
|
max_width = 0
|
||||||
lines = self._multiline_split(text)
|
lines = self._multiline_split(text)
|
||||||
|
|
|
@ -143,10 +143,10 @@ class FreeTypeFont(object):
|
||||||
def getoffset(self, text):
|
def getoffset(self, text):
|
||||||
return self.font.getsize(text)[1]
|
return self.font.getsize(text)[1]
|
||||||
|
|
||||||
def getmask(self, text, mode="", direction=None, features=[]):
|
def getmask(self, text, mode="", direction=None, features=None):
|
||||||
return self.getmask2(text, mode, direction=direction, features=features)[0]
|
return self.getmask2(text, mode, direction=direction, features=features)[0]
|
||||||
|
|
||||||
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=[]):
|
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=None):
|
||||||
size, offset = self.font.getsize(text)
|
size, offset = self.font.getsize(text)
|
||||||
im = fill("L", size, 0)
|
im = fill("L", size, 0)
|
||||||
self.font.render(text, im.id, mode == "1", direction, features)
|
self.font.render(text, im.id, mode == "1", direction, features)
|
||||||
|
|
191
_imagingft.c
191
_imagingft.c
|
@ -41,6 +41,23 @@
|
||||||
#define FT_ERRORDEF( e, v, s ) { e, s },
|
#define FT_ERRORDEF( e, v, s ) { e, s },
|
||||||
#define FT_ERROR_START_LIST {
|
#define FT_ERROR_START_LIST {
|
||||||
#define FT_ERROR_END_LIST { 0, 0 } };
|
#define FT_ERROR_END_LIST { 0, 0 } };
|
||||||
|
#ifdef HAVE_RAQM
|
||||||
|
#include <raqm.h>
|
||||||
|
#else
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RAQM_DIRECTION_DEFAULT,
|
||||||
|
RAQM_DIRECTION_RTL,
|
||||||
|
RAQM_DIRECTION_LTR,
|
||||||
|
RAQM_DIRECTION_TTB
|
||||||
|
} raqm_direction_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int index, x_offset, x_advance, y_offset;
|
||||||
|
unsigned int cluster;
|
||||||
|
} GlyphInfo;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int code;
|
int code;
|
||||||
|
@ -48,7 +65,6 @@ struct {
|
||||||
} ft_errors[] =
|
} ft_errors[] =
|
||||||
|
|
||||||
#include FT_ERRORS_H
|
#include FT_ERRORS_H
|
||||||
#include "raqm.h"
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* font objects */
|
/* font objects */
|
||||||
|
@ -322,31 +338,17 @@ font_getabc(FontObject* self, PyObject* args)
|
||||||
return Py_BuildValue("ddd", a, b, c);
|
return Py_BuildValue("ddd", a, b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
font_render(FontObject* self, PyObject* args)
|
|
||||||
{
|
|
||||||
int i, x, y;
|
|
||||||
Imaging im;
|
|
||||||
int index, error, ascender;
|
|
||||||
int load_flags;
|
|
||||||
unsigned char *source;
|
|
||||||
FT_GlyphSlot glyph;
|
|
||||||
/* render string into given buffer (the buffer *must* have
|
|
||||||
the right size, or this will crash) */
|
|
||||||
PyObject* string;
|
|
||||||
Py_ssize_t id;
|
|
||||||
int mask = 0;
|
|
||||||
int temp;
|
|
||||||
int xx, x0, x1;
|
|
||||||
const char *dir = NULL;
|
|
||||||
raqm_direction_t direction;
|
|
||||||
raqm_t *rq;
|
|
||||||
size_t count;
|
|
||||||
raqm_glyph_t *glyph_info;
|
|
||||||
PyObject *features = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "On|izO:render", &string, &id, &mask, &dir, &features))
|
static size_t
|
||||||
return NULL;
|
text_layout(PyObject* string, FontObject* self, const char* dir,
|
||||||
|
PyObject *features ,GlyphInfo **glyph_info, int mask)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_RAQM
|
||||||
|
int i = 0;
|
||||||
|
raqm_t *rq;
|
||||||
|
size_t count = 0;
|
||||||
|
raqm_glyph_t *glyphs;
|
||||||
|
raqm_direction_t direction;
|
||||||
|
|
||||||
rq = raqm_create();
|
rq = raqm_create();
|
||||||
if (rq == NULL) {
|
if (rq == NULL) {
|
||||||
|
@ -354,7 +356,6 @@ font_render(FontObject* self, PyObject* args)
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (PyUnicode_Check(string)) {
|
if (PyUnicode_Check(string)) {
|
||||||
Py_UNICODE *text = PyUnicode_AS_UNICODE(string);
|
Py_UNICODE *text = PyUnicode_AS_UNICODE(string);
|
||||||
Py_ssize_t size = PyUnicode_GET_SIZE(string);
|
Py_ssize_t size = PyUnicode_GET_SIZE(string);
|
||||||
|
@ -397,7 +398,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (features) {
|
if (features != Py_None) {
|
||||||
int len;
|
int len;
|
||||||
PyObject *seq = PySequence_Fast(features, "expected a sequence");
|
PyObject *seq = PySequence_Fast(features, "expected a sequence");
|
||||||
if (!seq) {
|
if (!seq) {
|
||||||
|
@ -420,8 +421,10 @@ font_render(FontObject* self, PyObject* args)
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyUnicode_Check(item)) {
|
if (PyUnicode_Check(item)) {
|
||||||
bytes = PyUnicode_AsUTF8String(item);
|
bytes = PyUnicode_AsUTF8String(item);
|
||||||
|
if (bytes == NULL)
|
||||||
|
goto failed;
|
||||||
feature = PyBytes_AS_STRING(bytes);
|
feature = PyBytes_AS_STRING(bytes);
|
||||||
size = PyBytes_GET_SIZE(bytes);
|
size = PyBytes_GET_SIZE(bytes);
|
||||||
}
|
}
|
||||||
|
@ -448,12 +451,121 @@ font_render(FontObject* self, PyObject* args)
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph_info = raqm_get_glyphs(rq, &count);
|
glyphs = raqm_get_glyphs(rq, &count);
|
||||||
if (glyph_info == NULL) {
|
if (glyphs == NULL) {
|
||||||
PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
|
PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
|
||||||
|
count = 0;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(*glyph_info) = PyMem_New(GlyphInfo, count);
|
||||||
|
if ((*glyph_info) == NULL) {
|
||||||
|
PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed");
|
||||||
|
count = 0;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
(*glyph_info)[i].index = glyphs[i].index;
|
||||||
|
(*glyph_info)[i].x_offset = glyphs[i].x_offset;
|
||||||
|
(*glyph_info)[i].x_advance = glyphs[i].x_advance;
|
||||||
|
(*glyph_info)[i].y_offset = glyphs[i].y_offset;
|
||||||
|
(*glyph_info)[i].cluster = glyphs[i].cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
failed:
|
||||||
|
raqm_destroy (rq);
|
||||||
|
return count;
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (features != Py_None || dir != NULL)
|
||||||
|
PyErr_SetString(PyExc_KeyError, "Raqm is missing.");
|
||||||
|
|
||||||
|
int error, load_flags;
|
||||||
|
FT_ULong ch;
|
||||||
|
Py_ssize_t count;
|
||||||
|
FT_GlyphSlot glyph;
|
||||||
|
FT_Bool kerning = FT_HAS_KERNING(self->face);
|
||||||
|
FT_UInt last_index = 0;
|
||||||
|
#if PY_VERSION_HEX >= 0x03000000
|
||||||
|
if (!PyUnicode_Check(string)) {
|
||||||
|
#else
|
||||||
|
if (!PyUnicode_Check(string) && !PyString_Check(string)) {
|
||||||
|
#endif
|
||||||
|
PyErr_SetString(PyExc_TypeError, "expected string");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
while (font_getchar(string, count, &ch))
|
||||||
|
count++;
|
||||||
|
if (count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
(*glyph_info) = PyMem_New(GlyphInfo, count);
|
||||||
|
if ((*glyph_info) == NULL) {
|
||||||
|
PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP;
|
||||||
|
if (mask)
|
||||||
|
load_flags |= FT_LOAD_TARGET_MONO;
|
||||||
|
int i;
|
||||||
|
for (i = 0; font_getchar(string, i, &ch); i++) {
|
||||||
|
(*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
|
||||||
|
error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
|
||||||
|
if (error) {
|
||||||
|
geterror(error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
glyph = self->face->glyph;
|
||||||
|
(*glyph_info)[i].x_offset=0;
|
||||||
|
(*glyph_info)[i].y_offset=0;
|
||||||
|
if (kerning && last_index && (*glyph_info)[i].index) {
|
||||||
|
FT_Vector delta;
|
||||||
|
if (FT_Get_Kerning(self->face, last_index, (*glyph_info)[i].index,
|
||||||
|
ft_kerning_default,&delta) == 0)
|
||||||
|
(*glyph_info)[i-1].x_advance += PIXEL(delta.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*glyph_info)[i].x_advance = glyph->metrics.horiAdvance;
|
||||||
|
last_index = (*glyph_info)[i].index;
|
||||||
|
(*glyph_info)[i].cluster = ch;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
font_render(FontObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
int i, x, y;
|
||||||
|
Imaging im;
|
||||||
|
int index, error, ascender;
|
||||||
|
int load_flags;
|
||||||
|
unsigned char *source;
|
||||||
|
FT_GlyphSlot glyph;
|
||||||
|
/* render string into given buffer (the buffer *must* have
|
||||||
|
the right size, or this will crash) */
|
||||||
|
PyObject* string;
|
||||||
|
Py_ssize_t id;
|
||||||
|
int mask = 0;
|
||||||
|
int temp;
|
||||||
|
int xx, x0, x1;
|
||||||
|
const char *dir = NULL;
|
||||||
|
size_t count;
|
||||||
|
GlyphInfo *glyph_info;
|
||||||
|
PyObject *features = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "On|izO:render", &string, &id, &mask, &dir, &features))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
glyph_info = NULL;
|
||||||
|
count = text_layout(string, self, dir, features, &glyph_info, mask);
|
||||||
|
if (count == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
im = (Imaging) id;
|
im = (Imaging) id;
|
||||||
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
|
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
|
||||||
load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP;
|
load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP;
|
||||||
|
@ -464,10 +576,9 @@ font_render(FontObject* self, PyObject* args)
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
index = glyph_info[i].index;
|
index = glyph_info[i].index;
|
||||||
error = FT_Load_Glyph(self->face, index, load_flags);
|
error = FT_Load_Glyph(self->face, index, load_flags);
|
||||||
if (error) {
|
if (error)
|
||||||
geterror(error);
|
return geterror(error);
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
glyph = self->face->glyph;
|
glyph = self->face->glyph;
|
||||||
temp = (glyph->bitmap.rows - glyph->bitmap_top);
|
temp = (glyph->bitmap.rows - glyph->bitmap_top);
|
||||||
temp -= PIXEL(glyph_info[i].y_offset);
|
temp -= PIXEL(glyph_info[i].y_offset);
|
||||||
|
@ -481,10 +592,8 @@ font_render(FontObject* self, PyObject* args)
|
||||||
index = glyph_info[i].index;
|
index = glyph_info[i].index;
|
||||||
|
|
||||||
error = FT_Load_Glyph(self->face, index, load_flags);
|
error = FT_Load_Glyph(self->face, index, load_flags);
|
||||||
if (error){
|
if (error)
|
||||||
geterror(error);
|
return geterror(error);
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
glyph = self->face->glyph;
|
glyph = self->face->glyph;
|
||||||
|
|
||||||
|
@ -537,12 +646,8 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
x += PIXEL(glyph_info[i].x_advance);
|
x += PIXEL(glyph_info[i].x_advance);
|
||||||
}
|
}
|
||||||
|
PyMem_Del(glyph_info);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
failed:
|
|
||||||
raqm_destroy(rq);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
18
setup.py
18
setup.py
|
@ -519,8 +519,10 @@ class pil_build_ext(build_ext):
|
||||||
|
|
||||||
if feature.want('raqm'):
|
if feature.want('raqm'):
|
||||||
if _find_include_file(self, "raqm.h"):
|
if _find_include_file(self, "raqm.h"):
|
||||||
if _find_library_file(self, "raqm"):
|
if _find_library_file(self, "raqm") and \
|
||||||
feature.raqm = "raqm"
|
_find_library_file(self, "harfbuzz") and \
|
||||||
|
_find_library_file(self, "fribidi"):
|
||||||
|
feature.raqm = ["raqm", "harfbuzz", "fribidi"]
|
||||||
|
|
||||||
if feature.want('lcms'):
|
if feature.want('lcms'):
|
||||||
_dbg('Looking for lcms')
|
_dbg('Looking for lcms')
|
||||||
|
@ -600,12 +602,14 @@ class pil_build_ext(build_ext):
|
||||||
# additional libraries
|
# additional libraries
|
||||||
|
|
||||||
if feature.freetype:
|
if feature.freetype:
|
||||||
exts.append(Extension("PIL._imagingft",
|
libs = ["freetype"]
|
||||||
["_imagingft.c"],
|
defs = []
|
||||||
libraries=["freetype"]))
|
if feature.raqm:
|
||||||
if feature.freetype and feature.raqm:
|
libs.extend(feature.raqm)
|
||||||
|
defs.append(('HAVE_RAQM', None))
|
||||||
exts.append(Extension(
|
exts.append(Extension(
|
||||||
"PIL._imagingft", ["_imagingft.c"], libraries=["freetype", "fribidi" , "harfbuzz", "raqm"]))
|
"PIL._imagingft", ["_imagingft.c"], libraries=libs,
|
||||||
|
define_macros=defs))
|
||||||
|
|
||||||
if feature.lcms:
|
if feature.lcms:
|
||||||
extra = []
|
extra = []
|
||||||
|
|
Loading…
Reference in New Issue
Block a user