Skip to content

Commit

Permalink
Use fractional coordinates when drawing text
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Nov 8, 2022
1 parent 820214d commit 5471dc2
Show file tree
Hide file tree
Showing 16 changed files with 54 additions and 8 deletions.
Binary file modified Tests/images/test_anchor_multiline_mm_right.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_lm_center.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_lm_left.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_lm_right.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_mm_center.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_mm_left.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_mm_right.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_rm_center.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_rm_left.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/test_combine_multiline_rm_right.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/text_float_coord.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Tests/images/text_float_coord_1_alt.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Tests/test_imagedraw.py
Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions src/PIL/ImageDraw.py
Expand Up @@ -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,
Expand All @@ -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,
)
Expand All @@ -478,6 +483,7 @@ def draw_text(ink, stroke_width=0, stroke_offset=None):
stroke_width,
anchor,
ink,
start=start,
*args,
**kwargs,
)
Expand All @@ -490,7 +496,7 @@ def draw_text(ink, stroke_width=0, stroke_offset=None):
# extract mask and set text alpha
color, mask = mask, mask.getband(3)
color.fillband(3, (ink >> 24) & 0xFF)
x, y = (int(c) for c in coord)
x, y = coord
self.im.paste(color, (x, y, x + mask.size[0], y + mask.size[1]), mask)
else:
self.draw.draw_bitmap(coord, mask, ink)
Expand Down
19 changes: 17 additions & 2 deletions src/PIL/ImageFont.py
Expand Up @@ -26,6 +26,7 @@
#

import base64
import math
import os
import sys
import warnings
Expand Down Expand Up @@ -588,6 +589,7 @@ def getmask(
stroke_width=0,
anchor=None,
ink=0,
start=None,
):
"""
Create a bitmap for the text.
Expand Down Expand Up @@ -659,6 +661,7 @@ def getmask(
stroke_width=stroke_width,
anchor=anchor,
ink=ink,
start=start,
)[0]

def getmask2(
Expand All @@ -672,6 +675,7 @@ def getmask2(
stroke_width=0,
anchor=None,
ink=0,
start=None,
*args,
**kwargs,
):
Expand Down Expand Up @@ -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

Expand Down
12 changes: 8 additions & 4 deletions src/_imagingft.c
Expand Up @@ -777,21 +777,25 @@ 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,
&dir,
&features,
&lang,
&stroke_width,
&foreground_ink_long)) {
&foreground_ink_long,
&x_start,
&y_start)) {
return NULL;
}

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 5471dc2

Please sign in to comment.