mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 10:16:17 +03:00
add support for fonts with COLR data
This commit is contained in:
parent
877831be13
commit
82a28d12e2
|
@ -291,7 +291,7 @@ Methods
|
||||||
|
|
||||||
Draw a shape.
|
Draw a shape.
|
||||||
|
|
||||||
.. py:method:: ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None)
|
.. py:method:: ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)
|
||||||
|
|
||||||
Draws the string at the given position.
|
Draws the string at the given position.
|
||||||
|
|
||||||
|
@ -352,7 +352,12 @@ Methods
|
||||||
|
|
||||||
.. versionadded:: 6.2.0
|
.. versionadded:: 6.2.0
|
||||||
|
|
||||||
.. py:method:: ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None)
|
:param embedded_color: Whether to use embedded color info in COLR and CPAL tables.
|
||||||
|
|
||||||
|
.. versionadded:: 8.0.0
|
||||||
|
|
||||||
|
|
||||||
|
.. py:method:: ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)
|
||||||
|
|
||||||
Draws the string at the given position.
|
Draws the string at the given position.
|
||||||
|
|
||||||
|
@ -399,6 +404,19 @@ Methods
|
||||||
|
|
||||||
.. versionadded:: 6.0.0
|
.. versionadded:: 6.0.0
|
||||||
|
|
||||||
|
:param stroke_width: The width of the text stroke.
|
||||||
|
|
||||||
|
.. versionadded:: 6.2.0
|
||||||
|
|
||||||
|
:param stroke_fill: Color to use for the text stroke. If not given, will default to
|
||||||
|
the ``fill`` parameter.
|
||||||
|
|
||||||
|
.. versionadded:: 6.2.0
|
||||||
|
|
||||||
|
:param embedded_color: Whether to use embedded color info in COLR and CPAL tables.
|
||||||
|
|
||||||
|
.. versionadded:: 8.0.0
|
||||||
|
|
||||||
.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||||
|
|
||||||
Return the size of the given string, in pixels.
|
Return the size of the given string, in pixels.
|
||||||
|
|
|
@ -282,6 +282,7 @@ class ImageDraw:
|
||||||
language=None,
|
language=None,
|
||||||
stroke_width=0,
|
stroke_width=0,
|
||||||
stroke_fill=None,
|
stroke_fill=None,
|
||||||
|
embedded_color=False,
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
|
@ -299,8 +300,12 @@ class ImageDraw:
|
||||||
language,
|
language,
|
||||||
stroke_width,
|
stroke_width,
|
||||||
stroke_fill,
|
stroke_fill,
|
||||||
|
embedded_color,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if embedded_color and self.mode not in ("RGB", "RGBA"):
|
||||||
|
raise ValueError("Embedded color supported only in RGB and RGBA modes")
|
||||||
|
|
||||||
if font is None:
|
if font is None:
|
||||||
font = self.getfont()
|
font = self.getfont()
|
||||||
|
|
||||||
|
@ -311,16 +316,20 @@ class ImageDraw:
|
||||||
return ink
|
return ink
|
||||||
|
|
||||||
def draw_text(ink, stroke_width=0, stroke_offset=None):
|
def draw_text(ink, stroke_width=0, stroke_offset=None):
|
||||||
|
mode = self.fontmode
|
||||||
|
if stroke_width == 0 and embedded_color:
|
||||||
|
mode = "RGBA"
|
||||||
coord = xy
|
coord = xy
|
||||||
try:
|
try:
|
||||||
mask, offset = font.getmask2(
|
mask, offset = font.getmask2(
|
||||||
text,
|
text,
|
||||||
self.fontmode,
|
mode,
|
||||||
direction=direction,
|
direction=direction,
|
||||||
features=features,
|
features=features,
|
||||||
language=language,
|
language=language,
|
||||||
stroke_width=stroke_width,
|
stroke_width=stroke_width,
|
||||||
anchor=anchor,
|
anchor=anchor,
|
||||||
|
ink=ink,
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
@ -329,12 +338,13 @@ class ImageDraw:
|
||||||
try:
|
try:
|
||||||
mask = font.getmask(
|
mask = font.getmask(
|
||||||
text,
|
text,
|
||||||
self.fontmode,
|
mode,
|
||||||
direction,
|
direction,
|
||||||
features,
|
features,
|
||||||
language,
|
language,
|
||||||
stroke_width,
|
stroke_width,
|
||||||
anchor,
|
anchor,
|
||||||
|
ink,
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
@ -342,7 +352,15 @@ class ImageDraw:
|
||||||
mask = font.getmask(text)
|
mask = font.getmask(text)
|
||||||
if stroke_offset:
|
if stroke_offset:
|
||||||
coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
|
coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
|
||||||
self.draw.draw_bitmap(coord, mask, ink)
|
if mode == "RGBA":
|
||||||
|
# font.getmask2(mode="RGBA") returns color in RGB bands and mask in A
|
||||||
|
# extract mask and set text alpha
|
||||||
|
color, mask = mask, mask.getband(3)
|
||||||
|
color.fillband(3, (ink >> 24) & 0xFF)
|
||||||
|
coord2 = coord[0] + mask.size[0], coord[1] + mask.size[1]
|
||||||
|
self.im.paste(color, coord + coord2, mask)
|
||||||
|
else:
|
||||||
|
self.draw.draw_bitmap(coord, mask, ink)
|
||||||
|
|
||||||
ink = getink(fill)
|
ink = getink(fill)
|
||||||
if ink is not None:
|
if ink is not None:
|
||||||
|
@ -374,6 +392,7 @@ class ImageDraw:
|
||||||
language=None,
|
language=None,
|
||||||
stroke_width=0,
|
stroke_width=0,
|
||||||
stroke_fill=None,
|
stroke_fill=None,
|
||||||
|
embedded_color=False,
|
||||||
):
|
):
|
||||||
if direction == "ttb":
|
if direction == "ttb":
|
||||||
raise ValueError("ttb direction is unsupported for multiline text")
|
raise ValueError("ttb direction is unsupported for multiline text")
|
||||||
|
@ -440,6 +459,7 @@ class ImageDraw:
|
||||||
language=language,
|
language=language,
|
||||||
stroke_width=stroke_width,
|
stroke_width=stroke_width,
|
||||||
stroke_fill=stroke_fill,
|
stroke_fill=stroke_fill,
|
||||||
|
embedded_color=embedded_color,
|
||||||
)
|
)
|
||||||
top += line_spacing
|
top += line_spacing
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,7 @@ class FreeTypeFont:
|
||||||
"""
|
"""
|
||||||
# vertical offset is added for historical reasons
|
# vertical offset is added for historical reasons
|
||||||
# see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929
|
# see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929
|
||||||
size, offset = self.font.getsize(text, False, direction, features, language)
|
size, offset = self.font.getsize(text, "L", direction, features, language)
|
||||||
return (
|
return (
|
||||||
size[0] + stroke_width * 2,
|
size[0] + stroke_width * 2,
|
||||||
size[1] + stroke_width * 2 + offset[1],
|
size[1] + stroke_width * 2 + offset[1],
|
||||||
|
@ -348,12 +348,14 @@ class FreeTypeFont:
|
||||||
language=None,
|
language=None,
|
||||||
stroke_width=0,
|
stroke_width=0,
|
||||||
anchor=None,
|
anchor=None,
|
||||||
|
ink=0,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Create a bitmap for the text.
|
Create a bitmap for the text.
|
||||||
|
|
||||||
If the font uses antialiasing, the bitmap should have mode ``L`` and use a
|
If the font uses antialiasing, the bitmap should have mode ``L`` and use a
|
||||||
maximum value of 255. Otherwise, it should have mode ``1``.
|
maximum value of 255. If the font has embedded color data, the bitmap
|
||||||
|
should have mode ``RGBA``. Otherwise, it should have mode ``1``.
|
||||||
|
|
||||||
:param text: Text to render.
|
:param text: Text to render.
|
||||||
:param mode: Used by some graphics drivers to indicate what mode the
|
:param mode: Used by some graphics drivers to indicate what mode the
|
||||||
|
@ -402,6 +404,10 @@ class FreeTypeFont:
|
||||||
|
|
||||||
.. versionadded:: 8.0.0
|
.. versionadded:: 8.0.0
|
||||||
|
|
||||||
|
:param ink: Foreground ink for rendering in RGBA mode.
|
||||||
|
|
||||||
|
.. versionadded:: 8.0.0
|
||||||
|
|
||||||
:return: An internal PIL storage memory instance as defined by the
|
:return: An internal PIL storage memory instance as defined by the
|
||||||
:py:mod:`PIL.Image.core` interface module.
|
:py:mod:`PIL.Image.core` interface module.
|
||||||
"""
|
"""
|
||||||
|
@ -413,6 +419,7 @@ class FreeTypeFont:
|
||||||
language=language,
|
language=language,
|
||||||
stroke_width=stroke_width,
|
stroke_width=stroke_width,
|
||||||
anchor=anchor,
|
anchor=anchor,
|
||||||
|
ink=ink,
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
def getmask2(
|
def getmask2(
|
||||||
|
@ -425,6 +432,7 @@ class FreeTypeFont:
|
||||||
language=None,
|
language=None,
|
||||||
stroke_width=0,
|
stroke_width=0,
|
||||||
anchor=None,
|
anchor=None,
|
||||||
|
ink=0,
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
|
@ -432,7 +440,8 @@ class FreeTypeFont:
|
||||||
Create a bitmap for the text.
|
Create a bitmap for the text.
|
||||||
|
|
||||||
If the font uses antialiasing, the bitmap should have mode ``L`` and use a
|
If the font uses antialiasing, the bitmap should have mode ``L`` and use a
|
||||||
maximum value of 255. Otherwise, it should have mode ``1``.
|
maximum value of 255. If the font has embedded color data, the bitmap
|
||||||
|
should have mode ``RGBA``. Otherwise, it should have mode ``1``.
|
||||||
|
|
||||||
:param text: Text to render.
|
:param text: Text to render.
|
||||||
:param mode: Used by some graphics drivers to indicate what mode the
|
:param mode: Used by some graphics drivers to indicate what mode the
|
||||||
|
@ -481,18 +490,22 @@ class FreeTypeFont:
|
||||||
|
|
||||||
.. versionadded:: 8.0.0
|
.. versionadded:: 8.0.0
|
||||||
|
|
||||||
|
:param ink: Foreground ink for rendering in RGBA mode.
|
||||||
|
|
||||||
|
.. versionadded:: 8.0.0
|
||||||
|
|
||||||
:return: A tuple of an internal PIL storage memory instance as defined by the
|
:return: A tuple of an internal PIL storage memory instance as defined by the
|
||||||
:py:mod:`PIL.Image.core` interface module, and the text offset, the
|
:py:mod:`PIL.Image.core` interface module, and the text offset, the
|
||||||
gap between the starting coordinate and the first marking
|
gap between the starting coordinate and the first marking
|
||||||
"""
|
"""
|
||||||
size, offset = self.font.getsize(
|
size, offset = self.font.getsize(
|
||||||
text, mode == "1", direction, features, language, anchor
|
text, mode, direction, features, language, anchor
|
||||||
)
|
)
|
||||||
size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
|
size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
|
||||||
offset = offset[0] - stroke_width, offset[1] - stroke_width
|
offset = offset[0] - stroke_width, offset[1] - stroke_width
|
||||||
im = fill("L", size, 0)
|
im = fill("RGBA" if mode == "RGBA" else "L", size, 0)
|
||||||
self.font.render(
|
self.font.render(
|
||||||
text, im.id, mode == "1", direction, features, language, stroke_width
|
text, im.id, mode, direction, features, language, stroke_width, ink
|
||||||
)
|
)
|
||||||
return im, offset
|
return im, offset
|
||||||
|
|
||||||
|
|
123
src/_imagingft.c
123
src/_imagingft.c
|
@ -28,6 +28,9 @@
|
||||||
#include FT_STROKER_H
|
#include FT_STROKER_H
|
||||||
#include FT_MULTIPLE_MASTERS_H
|
#include FT_MULTIPLE_MASTERS_H
|
||||||
#include FT_SFNT_NAMES_H
|
#include FT_SFNT_NAMES_H
|
||||||
|
#ifdef FT_COLOR_H
|
||||||
|
#include FT_COLOR_H
|
||||||
|
#endif
|
||||||
|
|
||||||
#define KEEP_PY_UNICODE
|
#define KEEP_PY_UNICODE
|
||||||
|
|
||||||
|
@ -350,7 +353,7 @@ font_getchar(PyObject* string, int index, FT_ULong* char_out)
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||||
const char* lang, GlyphInfo **glyph_info, int mask)
|
const char* lang, GlyphInfo **glyph_info, int mask, int color)
|
||||||
{
|
{
|
||||||
size_t i = 0, count = 0, start = 0;
|
size_t i = 0, count = 0, start = 0;
|
||||||
raqm_t *rq;
|
raqm_t *rq;
|
||||||
|
@ -529,7 +532,7 @@ failed:
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||||
const char* lang, GlyphInfo **glyph_info, int mask)
|
const char* lang, GlyphInfo **glyph_info, int mask, int color)
|
||||||
{
|
{
|
||||||
int error, load_flags;
|
int error, load_flags;
|
||||||
FT_ULong ch;
|
FT_ULong ch;
|
||||||
|
@ -565,6 +568,11 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje
|
||||||
if (mask) {
|
if (mask) {
|
||||||
load_flags |= FT_LOAD_TARGET_MONO;
|
load_flags |= FT_LOAD_TARGET_MONO;
|
||||||
}
|
}
|
||||||
|
#ifdef FT_LOAD_COLOR
|
||||||
|
if (color) {
|
||||||
|
load_flags |= FT_LOAD_COLOR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
for (i = 0; font_getchar(string, i, &ch); i++) {
|
for (i = 0; font_getchar(string, i, &ch); i++) {
|
||||||
(*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
|
(*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
|
||||||
error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
|
error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
|
||||||
|
@ -595,14 +603,14 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||||
const char* lang, GlyphInfo **glyph_info, int mask)
|
const char* lang, GlyphInfo **glyph_info, int mask, int color)
|
||||||
{
|
{
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) {
|
if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) {
|
||||||
count = text_layout_raqm(string, self, dir, features, lang, glyph_info, mask);
|
count = text_layout_raqm(string, self, dir, features, lang, glyph_info, mask, color);
|
||||||
} else {
|
} else {
|
||||||
count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask);
|
count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask, color);
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -624,6 +632,8 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
size_t i, count; /* glyph_info index and length */
|
size_t i, count; /* glyph_info index and length */
|
||||||
int horizontal_dir; /* is primary axis horizontal? */
|
int horizontal_dir; /* is primary axis horizontal? */
|
||||||
int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
|
int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
|
||||||
|
int color = 0; /* is FT_LOAD_COLOR enabled? */
|
||||||
|
const char *mode = NULL;
|
||||||
const char *dir = NULL;
|
const char *dir = NULL;
|
||||||
const char *lang = NULL;
|
const char *lang = NULL;
|
||||||
const char *anchor = NULL;
|
const char *anchor = NULL;
|
||||||
|
@ -632,12 +642,15 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
|
|
||||||
/* calculate size and bearing for a given string */
|
/* calculate size and bearing for a given string */
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|izOzz:getsize", &string, &mask, &dir, &features, &lang, &anchor)) {
|
if (!PyArg_ParseTuple(args, "O|zzOzz:getsize", &string, &mode, &dir, &features, &lang, &anchor)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
|
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
|
||||||
|
|
||||||
|
mask = mode && strcmp(mode, "1") == 0;
|
||||||
|
color = mode && strcmp(mode, "RGBA") == 0;
|
||||||
|
|
||||||
if (anchor == NULL) {
|
if (anchor == NULL) {
|
||||||
anchor = horizontal_dir ? "la" : "lt";
|
anchor = horizontal_dir ? "la" : "lt";
|
||||||
}
|
}
|
||||||
|
@ -645,7 +658,7 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
goto bad_anchor;
|
goto bad_anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
|
count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -657,6 +670,11 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
if (mask) {
|
if (mask) {
|
||||||
load_flags |= FT_LOAD_TARGET_MONO;
|
load_flags |= FT_LOAD_TARGET_MONO;
|
||||||
}
|
}
|
||||||
|
#ifdef FT_LOAD_COLOR
|
||||||
|
if (color) {
|
||||||
|
load_flags |= FT_LOAD_COLOR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* text bounds are given by:
|
* text bounds are given by:
|
||||||
|
@ -834,7 +852,10 @@ font_render(FontObject* self, PyObject* args)
|
||||||
Py_ssize_t id;
|
Py_ssize_t id;
|
||||||
int horizontal_dir; /* is primary axis horizontal? */
|
int horizontal_dir; /* is primary axis horizontal? */
|
||||||
int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
|
int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
|
||||||
|
int color = 0; /* is FT_LOAD_COLOR enabled? */
|
||||||
int stroke_width = 0;
|
int stroke_width = 0;
|
||||||
|
PY_LONG_LONG foreground_ink = 0;
|
||||||
|
const char *mode = NULL;
|
||||||
const char *dir = NULL;
|
const char *dir = NULL;
|
||||||
const char *lang = NULL;
|
const char *lang = NULL;
|
||||||
PyObject *features = Py_None;
|
PyObject *features = Py_None;
|
||||||
|
@ -843,14 +864,28 @@ font_render(FontObject* self, PyObject* args)
|
||||||
/* render string into given buffer (the buffer *must* have
|
/* render string into given buffer (the buffer *must* have
|
||||||
the right size, or this will crash) */
|
the right size, or this will crash) */
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "On|izOzi:render", &string, &id, &mask, &dir, &features, &lang,
|
if (!PyArg_ParseTuple(args, "On|zzOziL:render", &string, &id, &mode, &dir, &features, &lang,
|
||||||
&stroke_width)) {
|
&stroke_width, &foreground_ink)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
|
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
|
||||||
|
|
||||||
count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
|
mask = mode && strcmp(mode, "1") == 0;
|
||||||
|
color = mode && strcmp(mode, "RGBA") == 0;
|
||||||
|
|
||||||
|
#ifdef FT_COLOR_H
|
||||||
|
if (color) {
|
||||||
|
FT_Color foreground_color;
|
||||||
|
foreground_color.red = (FT_Byte) (foreground_ink);
|
||||||
|
foreground_color.green = (FT_Byte) (foreground_ink >> 8);
|
||||||
|
foreground_color.blue = (FT_Byte) (foreground_ink >> 16);
|
||||||
|
foreground_color.alpha = (FT_Byte) 255; /* ink alpha is handled in ImageDraw.text */
|
||||||
|
FT_Palette_Set_Foreground_Color(self->face, foreground_color);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -874,6 +909,11 @@ font_render(FontObject* self, PyObject* args)
|
||||||
if (mask) {
|
if (mask) {
|
||||||
load_flags |= FT_LOAD_TARGET_MONO;
|
load_flags |= FT_LOAD_TARGET_MONO;
|
||||||
}
|
}
|
||||||
|
#ifdef FT_LOAD_COLOR
|
||||||
|
if (color) {
|
||||||
|
load_flags |= FT_LOAD_COLOR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* calculate x_min and y_max
|
* calculate x_min and y_max
|
||||||
|
@ -960,25 +1000,58 @@ font_render(FontObject* self, PyObject* args)
|
||||||
/* clip glyph bitmap height to target image bounds */
|
/* clip glyph bitmap height to target image bounds */
|
||||||
if (yy >= 0 && yy < im->ysize) {
|
if (yy >= 0 && yy < im->ysize) {
|
||||||
// blend this glyph into the buffer
|
// blend this glyph into the buffer
|
||||||
unsigned char *target = im->image8[yy] + xx;
|
if (color) {
|
||||||
if (mask) {
|
/* target[RGB] returns the color, target[A] returns the mask */
|
||||||
// use monochrome mask (on palette images, etc)
|
/* target bands get split again in ImageDraw.text */
|
||||||
int j, k, m = 128;
|
unsigned char *target = im->image[yy] + xx * 4;
|
||||||
for (j = k = 0; j < x1; j++) {
|
#ifdef FT_LOAD_COLOR
|
||||||
if (j >= x0 && (source[k] & m)) {
|
if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
|
||||||
target[j] = 255;
|
// paste color glyph
|
||||||
|
int k;
|
||||||
|
for (k = x0; k < x1; k++) {
|
||||||
|
if (target[k * 4 + 3] < source[k * 4 + 3]) {
|
||||||
|
/* unpremultiply BGRa to RGBA */
|
||||||
|
target[k * 4 + 0] = CLIP8((255 * (int)source[k * 4 + 2]) / source[k * 4 + 3]);
|
||||||
|
target[k * 4 + 1] = CLIP8((255 * (int)source[k * 4 + 1]) / source[k * 4 + 3]);
|
||||||
|
target[k * 4 + 2] = CLIP8((255 * (int)source[k * 4 + 0]) / source[k * 4 + 3]);
|
||||||
|
target[k * 4 + 3] = source[k * 4 + 3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!(m >>= 1)) {
|
} else
|
||||||
m = 128;
|
#endif
|
||||||
k++;
|
{ // pixel_mode should be FT_PIXEL_MODE_GRAY
|
||||||
|
// fill with ink
|
||||||
|
int k;
|
||||||
|
for (k = x0; k < x1; k++) {
|
||||||
|
if (target[k * 4 + 3] < source[k]) {
|
||||||
|
target[k * 4 + 0] = (unsigned char) (foreground_ink);
|
||||||
|
target[k * 4 + 1] = (unsigned char) (foreground_ink >> 8);
|
||||||
|
target[k * 4 + 2] = (unsigned char) (foreground_ink >> 16);
|
||||||
|
target[k * 4 + 3] = source[k];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// use antialiased rendering
|
unsigned char *target = im->image8[yy] + xx;
|
||||||
int k;
|
if (mask) {
|
||||||
for (k = x0; k < x1; k++) {
|
// use monochrome mask (on palette images, etc)
|
||||||
if (target[k] < source[k]) {
|
int j, k, m = 128;
|
||||||
target[k] = source[k];
|
for (j = k = 0; j < x1; j++) {
|
||||||
|
if (j >= x0 && (source[k] & m)) {
|
||||||
|
target[j] = 255;
|
||||||
|
}
|
||||||
|
if (!(m >>= 1)) {
|
||||||
|
m = 128;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use antialiased rendering
|
||||||
|
int k;
|
||||||
|
for (k = x0; k < x1; k++) {
|
||||||
|
if (target[k] < source[k]) {
|
||||||
|
target[k] = source[k];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user