diff --git a/Tests/images/test_anchor_multiline_mm_right.png b/Tests/images/test_anchor_multiline_mm_right.png index cf002b12cd0..7e98b8eac8d 100644 Binary files a/Tests/images/test_anchor_multiline_mm_right.png and b/Tests/images/test_anchor_multiline_mm_right.png differ diff --git a/Tests/images/test_combine_multiline_lm_center.png b/Tests/images/test_combine_multiline_lm_center.png index 7b1e9c4e42f..6a15130248a 100644 Binary files a/Tests/images/test_combine_multiline_lm_center.png and b/Tests/images/test_combine_multiline_lm_center.png differ diff --git a/Tests/images/test_combine_multiline_lm_left.png b/Tests/images/test_combine_multiline_lm_left.png index a26996c2dbe..8eb254fdf26 100644 Binary files a/Tests/images/test_combine_multiline_lm_left.png and b/Tests/images/test_combine_multiline_lm_left.png differ diff --git a/Tests/images/test_combine_multiline_lm_right.png b/Tests/images/test_combine_multiline_lm_right.png index 7caf5cb742a..cb640a7409f 100644 Binary files a/Tests/images/test_combine_multiline_lm_right.png and b/Tests/images/test_combine_multiline_lm_right.png differ diff --git a/Tests/images/test_combine_multiline_mm_center.png b/Tests/images/test_combine_multiline_mm_center.png index a859e9570c8..d1146b8b856 100644 Binary files a/Tests/images/test_combine_multiline_mm_center.png and b/Tests/images/test_combine_multiline_mm_center.png differ diff --git a/Tests/images/test_combine_multiline_mm_left.png b/Tests/images/test_combine_multiline_mm_left.png index aadb5191f0e..f539a8e62e6 100644 Binary files a/Tests/images/test_combine_multiline_mm_left.png and b/Tests/images/test_combine_multiline_mm_left.png differ diff --git a/Tests/images/test_combine_multiline_mm_right.png b/Tests/images/test_combine_multiline_mm_right.png index 8238d4ec8ca..02634163e1c 100644 Binary files a/Tests/images/test_combine_multiline_mm_right.png and b/Tests/images/test_combine_multiline_mm_right.png differ diff --git a/Tests/images/test_combine_multiline_rm_center.png b/Tests/images/test_combine_multiline_rm_center.png index 7568dd63a33..4cce8f6a00e 100644 Binary files a/Tests/images/test_combine_multiline_rm_center.png and b/Tests/images/test_combine_multiline_rm_center.png differ diff --git a/Tests/images/test_combine_multiline_rm_left.png b/Tests/images/test_combine_multiline_rm_left.png index b8c3b5b143d..93d8162b3bf 100644 Binary files a/Tests/images/test_combine_multiline_rm_left.png and b/Tests/images/test_combine_multiline_rm_left.png differ diff --git a/Tests/images/test_combine_multiline_rm_right.png b/Tests/images/test_combine_multiline_rm_right.png index 14c478a72d0..6c4634560ed 100644 Binary files a/Tests/images/test_combine_multiline_rm_right.png and b/Tests/images/test_combine_multiline_rm_right.png differ diff --git a/Tests/images/text_float_coord.png b/Tests/images/text_float_coord.png index 49468698cd4..d2270826a5b 100644 Binary files a/Tests/images/text_float_coord.png and b/Tests/images/text_float_coord.png differ diff --git a/Tests/images/text_float_coord_1_alt.png b/Tests/images/text_float_coord_1_alt.png index 50bdac3d8f3..2287071ffab 100644 Binary files a/Tests/images/text_float_coord_1_alt.png and b/Tests/images/text_float_coord_1_alt.png differ diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 76b7c65cc37..4c4c41b7b51 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -1238,6 +1238,27 @@ def test_stroke_descender(): assert_image_similar_tofile(im, "Tests/images/imagedraw_stroke_descender.png", 6.76) +@skip_unless_feature("freetype2") +def test_split_word(): + # Arrange + im = Image.new("RGB", (230, 55)) + expected = im.copy() + expected_draw = ImageDraw.Draw(expected) + font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 48) + expected_draw.text((0, 0), "paradise", font=font) + + draw = ImageDraw.Draw(im) + + # Act + draw.text((0, 0), "par", font=font) + + length = draw.textlength("par", font=font) + draw.text((length, 0), "adise", font=font) + + # Assert + assert_image_equal(im, expected) + + @skip_unless_feature("freetype2") def test_stroke_multiline(): # Arrange diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index ff94f0ce3d6..837c353fad5 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -452,7 +452,11 @@ 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 = [] + start = [] + for i in range(2): + coord.append(int(xy[i])) + start.append(math.modf(xy[i])[0]) try: mask, offset = font.getmask2( text, @@ -463,6 +467,7 @@ def draw_text(ink, stroke_width=0, stroke_offset=None): stroke_width=stroke_width, anchor=anchor, ink=ink, + start=start, *args, **kwargs, ) @@ -478,6 +483,7 @@ def draw_text(ink, stroke_width=0, stroke_offset=None): stroke_width, anchor, ink, + start=start, *args, **kwargs, ) diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 457e906c872..c8de65be2d2 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -26,6 +26,7 @@ # import base64 +import math import os import sys import warnings @@ -588,6 +589,7 @@ def getmask( stroke_width=0, anchor=None, ink=0, + start=None, ): """ Create a bitmap for the text. @@ -659,6 +661,7 @@ def getmask( stroke_width=stroke_width, anchor=anchor, ink=ink, + start=start, )[0] def getmask2( @@ -672,6 +675,7 @@ def getmask2( stroke_width=0, anchor=None, ink=0, + start=None, *args, **kwargs, ): @@ -750,12 +754,23 @@ def getmask2( size, offset = self.font.getsize( text, mode, direction, features, language, anchor ) - size = size[0] + stroke_width * 2, size[1] + stroke_width * 2 + if start is None: + start = (0, 0) + size = tuple(math.ceil(size[i] + stroke_width * 2 + start[i]) for i in range(2)) offset = offset[0] - stroke_width, offset[1] - stroke_width Image._decompression_bomb_check(size) im = fill("RGBA" if mode == "RGBA" else "L", size, 0) self.font.render( - text, im.id, mode, direction, features, language, stroke_width, ink + text, + im.id, + mode, + direction, + features, + language, + stroke_width, + ink, + start[0], + start[1], ) return im, offset diff --git a/src/_imagingft.c b/src/_imagingft.c index bd409917601..b52d6353ebc 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -777,13 +777,15 @@ font_render(FontObject *self, PyObject *args) { const char *lang = NULL; PyObject *features = Py_None; PyObject *string; + float x_start = 0; + float y_start = 0; /* render string into given buffer (the buffer *must* have the right size, or this will crash) */ if (!PyArg_ParseTuple( args, - "On|zzOziL:render", + "On|zzOziLff:render", &string, &id, &mode, @@ -791,7 +793,9 @@ font_render(FontObject *self, PyObject *args) { &features, &lang, &stroke_width, - &foreground_ink_long)) { + &foreground_ink_long, + &x_start, + &y_start)) { return NULL; } @@ -876,8 +880,8 @@ font_render(FontObject *self, PyObject *args) { } /* set pen position to text origin */ - x = (-x_min + stroke_width) << 6; - y = (-y_max + (-stroke_width)) << 6; + x = (-x_min + stroke_width + x_start) * 64; + y = (-y_max + (-stroke_width) - y_start) * 64; if (stroker == NULL) { load_flags |= FT_LOAD_RENDER;