Anchor left when justifying words

This commit is contained in:
Andrew Murray 2025-04-17 20:56:02 +10:00
parent b955cee725
commit bc05a88ce6
4 changed files with 32 additions and 25 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -267,19 +267,21 @@ def test_render_multiline_text_align(
assert_image_similar_tofile(im, f"Tests/images/multiline_text{ext}.png", 0.01)
def test_render_multiline_text_align_justify_last_line(
def test_render_multiline_text_justify_anchor(
font: ImageFont.FreeTypeFont,
) -> None:
im = Image.new("RGB", (280, 60))
im = Image.new("RGB", (280, 240))
draw = ImageDraw.Draw(im)
draw.multiline_text(
(0, 0),
"hey you you are awesome\nthis\nlooks awkward",
font=font,
align="justify",
)
for xy, anchor in (((0, 0), "la"), ((140, 80), "ma"), ((280, 160), "ra")):
draw.multiline_text(
xy,
"hey you you are awesome\nthis looks awkward\nthis\nlooks awkward",
font=font,
anchor=anchor,
align="justify",
)
assert_image_equal_tofile(im, "Tests/images/multiline_text_justify_last_line.png")
assert_image_equal_tofile(im, "Tests/images/multiline_text_justify_anchor.png")
def test_unknown_align(font: ImageFont.FreeTypeFont) -> None:

View File

@ -702,8 +702,7 @@ class ImageDraw:
font_size: float | None,
) -> tuple[
ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont,
str,
list[tuple[tuple[float, float], AnyStr]],
list[tuple[tuple[float, float], str, AnyStr]],
]:
if direction == "ttb":
msg = "ttb direction is unsupported for multiline text"
@ -753,13 +752,7 @@ class ImageDraw:
left = xy[0]
width_difference = max_width - widths[idx]
# first align left by anchor
if anchor[0] == "m":
left -= width_difference / 2.0
elif anchor[0] == "r":
left -= width_difference
# then align by align parameter
# align by align parameter
if align in ("left", "justify"):
pass
elif align == "center":
@ -773,6 +766,12 @@ class ImageDraw:
if align == "justify" and width_difference != 0 and idx != len(lines) - 1:
words = line.split(" " if isinstance(text, str) else b" ")
if len(words) > 1:
# align left by anchor
if anchor[0] == "m":
left -= max_width / 2.0
elif anchor[0] == "r":
left -= max_width
word_widths = [
self.textlength(
word,
@ -784,17 +783,23 @@ class ImageDraw:
)
for word in words
]
word_anchor = "l" + anchor[1]
width_difference = max_width - sum(word_widths)
for i, word in enumerate(words):
parts.append(((left, top), word))
parts.append(((left, top), word_anchor, word))
left += word_widths[i] + width_difference / (len(words) - 1)
top += line_spacing
continue
parts.append(((left, top), line))
# align left by anchor
if anchor[0] == "m":
left -= width_difference / 2.0
elif anchor[0] == "r":
left -= width_difference
parts.append(((left, top), anchor, line))
top += line_spacing
return font, anchor, parts
return font, parts
def multiline_text(
self,
@ -819,7 +824,7 @@ class ImageDraw:
*,
font_size: float | None = None,
) -> None:
font, anchor, lines = self._prepare_multiline_text(
font, lines = self._prepare_multiline_text(
xy,
text,
font,
@ -834,7 +839,7 @@ class ImageDraw:
font_size,
)
for xy, line in lines:
for xy, anchor, line in lines:
self.text(
xy,
line,
@ -949,7 +954,7 @@ class ImageDraw:
*,
font_size: float | None = None,
) -> tuple[float, float, float, float]:
font, anchor, lines = self._prepare_multiline_text(
font, lines = self._prepare_multiline_text(
xy,
text,
font,
@ -966,7 +971,7 @@ class ImageDraw:
bbox: tuple[float, float, float, float] | None = None
for xy, line in lines:
for xy, anchor, line in lines:
bbox_line = self.textbbox(
xy,
line,