Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Tests/images/text_mono.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from .helper import (
assert_image_equal,
assert_image_equal_tofile,
assert_image_similar,
assert_image_similar_tofile,
is_pypy,
Expand Down Expand Up @@ -724,3 +725,19 @@ def _check_text(font, path, epsilon):
@skip_unless_feature("raqm")
class TestImageFont_RaqmLayout(TestImageFont):
LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM


def test_render_mono_size():
# issue 4177

if distutils.version.StrictVersion(ImageFont.core.freetype2_version) < "2.4":
pytest.skip("Different metrics")

im = Image.new("P", (100, 30), "white")
draw = ImageDraw.Draw(im)
ttf = ImageFont.truetype(
"Tests/fonts/DejaVuSans.ttf", 18, layout_engine=ImageFont.LAYOUT_BASIC
)

draw.text((10, 10), "r" * 10, "black", ttf)
assert_image_equal_tofile(im, "Tests/images/text_mono.gif")
6 changes: 4 additions & 2 deletions src/PIL/ImageFont.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def getsize(

:return: (width, height)
"""
size, offset = self.font.getsize(text, direction, features, language)
size, offset = self.font.getsize(text, False, direction, features, language)
return (
size[0] + stroke_width * 2 + offset[0],
size[1] + stroke_width * 2 + offset[1],
Expand Down Expand Up @@ -468,7 +468,9 @@ def getmask2(
:py:mod:`PIL.Image.core` interface module, and the text offset, the
gap between the starting coordinate and the first marking
"""
size, offset = self.font.getsize(text, direction, features, language)
size, offset = self.font.getsize(
text, mode == "1", direction, features, language
)
size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
im = fill("L", size, 0)
self.font.render(
Expand Down
12 changes: 9 additions & 3 deletions src/_imagingft.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,8 @@ font_getsize(FontObject* self, PyObject* args)
FT_Face face;
int xoffset, yoffset;
int horizontal_dir;
int mask = 0;
int load_flags;
const char *dir = NULL;
const char *lang = NULL;
size_t i, count;
Expand All @@ -614,11 +616,11 @@ font_getsize(FontObject* self, PyObject* args)
/* calculate size and bearing for a given string */

PyObject* string;
if (!PyArg_ParseTuple(args, "O|zOz:getsize", &string, &dir, &features, &lang)) {
if (!PyArg_ParseTuple(args, "O|izOz:getsize", &string, &mask, &dir, &features, &lang)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add the new parameter to the end, to maintain compatibility?

People have been calling ImageFont.font.getsize directly. A quick example:

font = ImageFont.truetype(fontname, fontsize)
limits = font.getsize(text)

Copy link
Contributor Author

@nulano nulano Jun 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linked and quoted example is the Python-layer function. It looks confusing as the code refers to the FreeTypeFont object as font, but updated function would have to be called with font.font.getsize(...). The same is true for the search results in the first few pages.

There are three functions concerning the size of text (ignoring the multiline variants):

ImageDraw.Draw.textsize(...)
ImageFont.FreeTypeFont.getsize(...)  # the Python version; I did not update this
ImageFont.FreeTypeFont.font.getsize(...)  # the C version; updated by this PR

The equivalent code would be:

font = ImageFont.truetype(...)
font.getsize(...)  # the Python function
font.font.getsize(...)  # the C function

I did not update the Python function as I think it would confusing to have the arguments in a different order, but not backwards compatible to add it at the front (suggestions are welcome).

If you still think the C function is a concern, would something with PyArg_ParseTupleAndKeywords be a good solution (i.e. making all future additions kwarg only)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I think we're fine to change this then. The C API is internal and doesn't need to maintain backwards compatibility.

return NULL;
}

count = text_layout(string, self, dir, features, lang, &glyph_info, 0);
count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
if (PyErr_Occurred()) {
return NULL;
}
Expand All @@ -637,7 +639,11 @@ font_getsize(FontObject* self, PyObject* args)
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960
* Yifu Yu<root@jackyyf.com>, 2014-10-15
*/
error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
load_flags = FT_LOAD_NO_BITMAP;
if (mask) {
load_flags |= FT_LOAD_TARGET_MONO;
}
error = FT_Load_Glyph(face, index, load_flags);
if (error) {
return geterror(error);
}
Expand Down