mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 18:06:18 +03:00
added layout engine switch
This commit is contained in:
parent
f371ca07f4
commit
b8c04de043
|
@ -41,6 +41,9 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
core = _imagingft_not_installed()
|
core = _imagingft_not_installed()
|
||||||
|
|
||||||
|
LAYOUT_BASIC = 0
|
||||||
|
LAYOUT_RAQM = 1
|
||||||
|
|
||||||
# FIXME: add support for pilfont2 format (see FontFile.py)
|
# FIXME: add support for pilfont2 format (see FontFile.py)
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -115,7 +118,8 @@ class ImageFont(object):
|
||||||
class FreeTypeFont(object):
|
class FreeTypeFont(object):
|
||||||
"FreeType font wrapper (requires _imagingft service)"
|
"FreeType font wrapper (requires _imagingft service)"
|
||||||
|
|
||||||
def __init__(self, font=None, size=10, index=0, encoding=""):
|
def __init__(self, font=None, size=10, index=0, encoding="",
|
||||||
|
layout_engine=None):
|
||||||
# FIXME: use service provider instead
|
# FIXME: use service provider instead
|
||||||
|
|
||||||
self.path = font
|
self.path = font
|
||||||
|
@ -123,12 +127,21 @@ class FreeTypeFont(object):
|
||||||
self.index = index
|
self.index = index
|
||||||
self.encoding = encoding
|
self.encoding = encoding
|
||||||
|
|
||||||
|
if layout_engine not in (LAYOUT_BASIC, LAYOUT_RAQM):
|
||||||
|
layout_engine = LAYOUT_BASIC
|
||||||
|
if core.HAVE_RAQM:
|
||||||
|
layout_engine = LAYOUT_RAQM
|
||||||
|
if layout_engine == LAYOUT_RAQM and not core.HAVE_RAQM:
|
||||||
|
layout_engine = LAYOUT_BASIC
|
||||||
|
|
||||||
|
self.layout_engine = layout_engine
|
||||||
|
|
||||||
if isPath(font):
|
if isPath(font):
|
||||||
self.font = core.getfont(font, size, index, encoding)
|
self.font = core.getfont(font, size, index, encoding, layout_engine=layout_engine)
|
||||||
else:
|
else:
|
||||||
self.font_bytes = font.read()
|
self.font_bytes = font.read()
|
||||||
self.font = core.getfont(
|
self.font = core.getfont(
|
||||||
"", size, index, encoding, self.font_bytes)
|
"", size, index, encoding, self.font_bytes, layout_engine)
|
||||||
|
|
||||||
def getname(self):
|
def getname(self):
|
||||||
return self.font.family, self.font.style
|
return self.font.family, self.font.style
|
||||||
|
@ -152,7 +165,8 @@ class FreeTypeFont(object):
|
||||||
self.font.render(text, im.id, mode == "1", direction, features)
|
self.font.render(text, im.id, mode == "1", direction, features)
|
||||||
return im, offset
|
return im, offset
|
||||||
|
|
||||||
def font_variant(self, font=None, size=None, index=None, encoding=None):
|
def font_variant(self, font=None, size=None, index=None, encoding=None,
|
||||||
|
layout_engine=None):
|
||||||
"""
|
"""
|
||||||
Create a copy of this FreeTypeFont object,
|
Create a copy of this FreeTypeFont object,
|
||||||
using any specified arguments to override the settings.
|
using any specified arguments to override the settings.
|
||||||
|
@ -165,8 +179,9 @@ class FreeTypeFont(object):
|
||||||
return FreeTypeFont(font=self.path if font is None else font,
|
return FreeTypeFont(font=self.path if font is None else font,
|
||||||
size=self.size if size is None else size,
|
size=self.size if size is None else size,
|
||||||
index=self.index if index is None else index,
|
index=self.index if index is None else index,
|
||||||
encoding=self.encoding if encoding is None else
|
encoding=self.encoding if encoding is None else encoding,
|
||||||
encoding)
|
layout_engine=self.layout_engine if layout_engine is None else layout_engine
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TransposedFont(object):
|
class TransposedFont(object):
|
||||||
|
@ -212,7 +227,8 @@ def load(filename):
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
def truetype(font=None, size=10, index=0, encoding=""):
|
def truetype(font=None, size=10, index=0, encoding="",
|
||||||
|
layout_engine=None):
|
||||||
"""
|
"""
|
||||||
Load a TrueType or OpenType font file, and create a font object.
|
Load a TrueType or OpenType font file, and create a font object.
|
||||||
This function loads a font object from the given file, and creates
|
This function loads a font object from the given file, and creates
|
||||||
|
@ -230,12 +246,14 @@ def truetype(font=None, size=10, index=0, encoding=""):
|
||||||
Symbol), "ADOB" (Adobe Standard), "ADBE" (Adobe Expert),
|
Symbol), "ADOB" (Adobe Standard), "ADBE" (Adobe Expert),
|
||||||
and "armn" (Apple Roman). See the FreeType documentation
|
and "armn" (Apple Roman). See the FreeType documentation
|
||||||
for more information.
|
for more information.
|
||||||
|
:param layout_engine: Which layout engine to use, if available:
|
||||||
|
`ImageFont.LAYOUT_BASIC` or `ImageFont.LAYOUT_RAQM`.
|
||||||
:return: A font object.
|
:return: A font object.
|
||||||
:exception IOError: If the file could not be read.
|
:exception IOError: If the file could not be read.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return FreeTypeFont(font, size, index, encoding)
|
return FreeTypeFont(font, size, index, encoding, layout_engine)
|
||||||
except IOError:
|
except IOError:
|
||||||
ttf_filename = os.path.basename(font)
|
ttf_filename = os.path.basename(font)
|
||||||
|
|
||||||
|
@ -266,16 +284,16 @@ def truetype(font=None, size=10, index=0, encoding=""):
|
||||||
for walkfilename in walkfilenames:
|
for walkfilename in walkfilenames:
|
||||||
if ext and walkfilename == ttf_filename:
|
if ext and walkfilename == ttf_filename:
|
||||||
fontpath = os.path.join(walkroot, walkfilename)
|
fontpath = os.path.join(walkroot, walkfilename)
|
||||||
return FreeTypeFont(fontpath, size, index, encoding)
|
return FreeTypeFont(fontpath, size, index, encoding, layout_engine)
|
||||||
elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename:
|
elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename:
|
||||||
fontpath = os.path.join(walkroot, walkfilename)
|
fontpath = os.path.join(walkroot, walkfilename)
|
||||||
if os.path.splitext(fontpath)[1] == '.ttf':
|
if os.path.splitext(fontpath)[1] == '.ttf':
|
||||||
return FreeTypeFont(fontpath, size, index, encoding)
|
return FreeTypeFont(fontpath, size, index, encoding, layout_engine)
|
||||||
if not ext and first_font_with_a_different_extension is None:
|
if not ext and first_font_with_a_different_extension is None:
|
||||||
first_font_with_a_different_extension = fontpath
|
first_font_with_a_different_extension = fontpath
|
||||||
if first_font_with_a_different_extension:
|
if first_font_with_a_different_extension:
|
||||||
return FreeTypeFont(first_font_with_a_different_extension, size,
|
return FreeTypeFont(first_font_with_a_different_extension, size,
|
||||||
index, encoding)
|
index, encoding, layout_engine)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -379,12 +379,12 @@ try:
|
||||||
# Make a copy of FreeTypeFont so we can patch the original
|
# Make a copy of FreeTypeFont so we can patch the original
|
||||||
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
|
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
|
||||||
with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font):
|
with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font):
|
||||||
def loadable_font(filepath, size, index, encoding):
|
def loadable_font(filepath, size, index, encoding, *args, **kwargs):
|
||||||
if filepath == path_to_fake:
|
if filepath == path_to_fake:
|
||||||
return ImageFont._FreeTypeFont(FONT_PATH, size, index,
|
return ImageFont._FreeTypeFont(FONT_PATH, size, index,
|
||||||
encoding)
|
encoding, *args, **kwargs)
|
||||||
return ImageFont._FreeTypeFont(filepath, size, index,
|
return ImageFont._FreeTypeFont(filepath, size, index,
|
||||||
encoding)
|
encoding, *args, **kwargs)
|
||||||
with SimplePatcher(ImageFont, 'FreeTypeFont', loadable_font):
|
with SimplePatcher(ImageFont, 'FreeTypeFont', loadable_font):
|
||||||
font = ImageFont.truetype(fontname)
|
font = ImageFont.truetype(fontname)
|
||||||
# Make sure it's loaded
|
# Make sure it's loaded
|
||||||
|
|
19
_imagingft.c
19
_imagingft.c
|
@ -45,6 +45,9 @@
|
||||||
#include <raqm.h>
|
#include <raqm.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LAYOUT_FALLBACK 0
|
||||||
|
#define LAYOUT_RAQM 1
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int index, x_offset, x_advance, y_offset;
|
int index, x_offset, x_advance, y_offset;
|
||||||
|
@ -67,6 +70,7 @@ typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
unsigned char *font_bytes;
|
unsigned char *font_bytes;
|
||||||
|
int layout_engine;
|
||||||
} FontObject;
|
} FontObject;
|
||||||
|
|
||||||
static PyTypeObject Font_Type;
|
static PyTypeObject Font_Type;
|
||||||
|
@ -100,11 +104,13 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
char* filename = NULL;
|
char* filename = NULL;
|
||||||
int size;
|
int size;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
int layout_engine = 0;
|
||||||
unsigned char* encoding;
|
unsigned char* encoding;
|
||||||
unsigned char* font_bytes;
|
unsigned char* font_bytes;
|
||||||
int font_bytes_size = 0;
|
int font_bytes_size = 0;
|
||||||
static char* kwlist[] = {
|
static char* kwlist[] = {
|
||||||
"filename", "size", "index", "encoding", "font_bytes", NULL
|
"filename", "size", "index", "encoding", "font_bytes",
|
||||||
|
"layout_engine", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!library) {
|
if (!library) {
|
||||||
|
@ -115,10 +121,10 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|iss#", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|iss#i", kwlist,
|
||||||
Py_FileSystemDefaultEncoding, &filename,
|
Py_FileSystemDefaultEncoding, &filename,
|
||||||
&size, &index, &encoding, &font_bytes,
|
&size, &index, &encoding, &font_bytes,
|
||||||
&font_bytes_size)) {
|
&font_bytes_size, &layout_engine)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +136,7 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
}
|
}
|
||||||
|
|
||||||
self->face = NULL;
|
self->face = NULL;
|
||||||
|
self->layout_engine = layout_engine;
|
||||||
|
|
||||||
if (filename && font_bytes_size <= 0) {
|
if (filename && font_bytes_size <= 0) {
|
||||||
self->font_bytes = NULL;
|
self->font_bytes = NULL;
|
||||||
|
@ -409,7 +416,11 @@ text_layout(PyObject* string, FontObject* self, const char* dir,
|
||||||
{
|
{
|
||||||
size_t count;
|
size_t count;
|
||||||
#ifdef HAVE_RAQM
|
#ifdef HAVE_RAQM
|
||||||
count = text_layout_raqm(string, self, dir, features, glyph_info, mask);
|
if (self->layout_engine == LAYOUT_RAQM) {
|
||||||
|
count = text_layout_raqm(string, self, dir, features, glyph_info, mask);
|
||||||
|
} else {
|
||||||
|
count = text_layout_fallback(string, self, dir, features, glyph_info, mask);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
count = text_layout_fallback(string, self, dir, features, glyph_info, mask);
|
count = text_layout_fallback(string, self, dir, features, glyph_info, mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user