mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-10 16:40:51 +03:00
Moved common multiline code into _prepare_multiline_text
This commit is contained in:
parent
9a4f39588d
commit
7093de46a7
|
@ -557,21 +557,6 @@ class ImageDraw:
|
|||
|
||||
return split_character in text
|
||||
|
||||
def _multiline_split(self, text: AnyStr) -> list[AnyStr]:
|
||||
return text.split("\n" if isinstance(text, str) else b"\n")
|
||||
|
||||
def _multiline_spacing(
|
||||
self,
|
||||
font: ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont,
|
||||
spacing: float,
|
||||
stroke_width: float,
|
||||
) -> float:
|
||||
return (
|
||||
self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3]
|
||||
+ stroke_width
|
||||
+ spacing
|
||||
)
|
||||
|
||||
def text(
|
||||
self,
|
||||
xy: tuple[float, float],
|
||||
|
@ -697,6 +682,101 @@ class ImageDraw:
|
|||
# Only draw normal text
|
||||
draw_text(ink)
|
||||
|
||||
def _prepare_multiline_text(
|
||||
self,
|
||||
xy: tuple[float, float],
|
||||
text: AnyStr,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
),
|
||||
anchor: str | None,
|
||||
spacing: float,
|
||||
align: str,
|
||||
direction: str | None,
|
||||
features: list[str] | None,
|
||||
language: str | None,
|
||||
stroke_width: float,
|
||||
embedded_color: bool,
|
||||
font_size: float | None,
|
||||
) -> tuple[
|
||||
ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont,
|
||||
str,
|
||||
list[tuple[tuple[float, float], AnyStr]],
|
||||
]:
|
||||
if direction == "ttb":
|
||||
msg = "ttb direction is unsupported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
||||
if anchor is None:
|
||||
anchor = "la"
|
||||
elif len(anchor) != 2:
|
||||
msg = "anchor must be a 2 character string"
|
||||
raise ValueError(msg)
|
||||
elif anchor[1] in "tb":
|
||||
msg = "anchor not supported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
||||
if font is None:
|
||||
font = self._getfont(font_size)
|
||||
|
||||
widths = []
|
||||
max_width: float = 0
|
||||
lines = text.split("\n" if isinstance(text, str) else b"\n")
|
||||
line_spacing = (
|
||||
self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3]
|
||||
+ stroke_width
|
||||
+ spacing
|
||||
)
|
||||
|
||||
for line in lines:
|
||||
line_width = self.textlength(
|
||||
line,
|
||||
font,
|
||||
direction=direction,
|
||||
features=features,
|
||||
language=language,
|
||||
embedded_color=embedded_color,
|
||||
)
|
||||
widths.append(line_width)
|
||||
max_width = max(max_width, line_width)
|
||||
|
||||
top = xy[1]
|
||||
if anchor[1] == "m":
|
||||
top -= (len(lines) - 1) * line_spacing / 2.0
|
||||
elif anchor[1] == "d":
|
||||
top -= (len(lines) - 1) * line_spacing
|
||||
|
||||
parts = []
|
||||
for idx, line in enumerate(lines):
|
||||
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
|
||||
if align == "left":
|
||||
pass
|
||||
elif align == "center":
|
||||
left += width_difference / 2.0
|
||||
elif align == "right":
|
||||
left += width_difference
|
||||
else:
|
||||
msg = 'align must be "left", "center" or "right"'
|
||||
raise ValueError(msg)
|
||||
|
||||
parts.append(((left, top), line))
|
||||
|
||||
top += line_spacing
|
||||
|
||||
return font, anchor, parts
|
||||
|
||||
def multiline_text(
|
||||
self,
|
||||
xy: tuple[float, float],
|
||||
|
@ -720,67 +800,24 @@ class ImageDraw:
|
|||
*,
|
||||
font_size: float | None = None,
|
||||
) -> None:
|
||||
if direction == "ttb":
|
||||
msg = "ttb direction is unsupported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
||||
if anchor is None:
|
||||
anchor = "la"
|
||||
elif len(anchor) != 2:
|
||||
msg = "anchor must be a 2 character string"
|
||||
raise ValueError(msg)
|
||||
elif anchor[1] in "tb":
|
||||
msg = "anchor not supported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
||||
if font is None:
|
||||
font = self._getfont(font_size)
|
||||
|
||||
widths = []
|
||||
max_width: float = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self._multiline_spacing(font, spacing, stroke_width)
|
||||
for line in lines:
|
||||
line_width = self.textlength(
|
||||
line,
|
||||
font,
|
||||
direction=direction,
|
||||
features=features,
|
||||
language=language,
|
||||
embedded_color=embedded_color,
|
||||
)
|
||||
widths.append(line_width)
|
||||
max_width = max(max_width, line_width)
|
||||
|
||||
top = xy[1]
|
||||
if anchor[1] == "m":
|
||||
top -= (len(lines) - 1) * line_spacing / 2.0
|
||||
elif anchor[1] == "d":
|
||||
top -= (len(lines) - 1) * line_spacing
|
||||
|
||||
for idx, line in enumerate(lines):
|
||||
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
|
||||
if align == "left":
|
||||
pass
|
||||
elif align == "center":
|
||||
left += width_difference / 2.0
|
||||
elif align == "right":
|
||||
left += width_difference
|
||||
else:
|
||||
msg = 'align must be "left", "center" or "right"'
|
||||
raise ValueError(msg)
|
||||
font, anchor, lines = self._prepare_multiline_text(
|
||||
xy,
|
||||
text,
|
||||
font,
|
||||
anchor,
|
||||
spacing,
|
||||
align,
|
||||
direction,
|
||||
features,
|
||||
language,
|
||||
stroke_width,
|
||||
embedded_color,
|
||||
font_size,
|
||||
)
|
||||
|
||||
for xy, line in lines:
|
||||
self.text(
|
||||
(left, top),
|
||||
xy,
|
||||
line,
|
||||
fill,
|
||||
font,
|
||||
|
@ -792,7 +829,6 @@ class ImageDraw:
|
|||
stroke_fill=stroke_fill,
|
||||
embedded_color=embedded_color,
|
||||
)
|
||||
top += line_spacing
|
||||
|
||||
def textlength(
|
||||
self,
|
||||
|
@ -894,69 +930,26 @@ class ImageDraw:
|
|||
*,
|
||||
font_size: float | None = None,
|
||||
) -> tuple[float, float, float, float]:
|
||||
if direction == "ttb":
|
||||
msg = "ttb direction is unsupported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
||||
if anchor is None:
|
||||
anchor = "la"
|
||||
elif len(anchor) != 2:
|
||||
msg = "anchor must be a 2 character string"
|
||||
raise ValueError(msg)
|
||||
elif anchor[1] in "tb":
|
||||
msg = "anchor not supported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
||||
if font is None:
|
||||
font = self._getfont(font_size)
|
||||
|
||||
widths = []
|
||||
max_width: float = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self._multiline_spacing(font, spacing, stroke_width)
|
||||
for line in lines:
|
||||
line_width = self.textlength(
|
||||
line,
|
||||
font,
|
||||
direction=direction,
|
||||
features=features,
|
||||
language=language,
|
||||
embedded_color=embedded_color,
|
||||
)
|
||||
widths.append(line_width)
|
||||
max_width = max(max_width, line_width)
|
||||
|
||||
top = xy[1]
|
||||
if anchor[1] == "m":
|
||||
top -= (len(lines) - 1) * line_spacing / 2.0
|
||||
elif anchor[1] == "d":
|
||||
top -= (len(lines) - 1) * line_spacing
|
||||
font, anchor, lines = self._prepare_multiline_text(
|
||||
xy,
|
||||
text,
|
||||
font,
|
||||
anchor,
|
||||
spacing,
|
||||
align,
|
||||
direction,
|
||||
features,
|
||||
language,
|
||||
stroke_width,
|
||||
embedded_color,
|
||||
font_size,
|
||||
)
|
||||
|
||||
bbox: tuple[float, float, float, float] | None = None
|
||||
|
||||
for idx, line in enumerate(lines):
|
||||
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
|
||||
if align == "left":
|
||||
pass
|
||||
elif align == "center":
|
||||
left += width_difference / 2.0
|
||||
elif align == "right":
|
||||
left += width_difference
|
||||
else:
|
||||
msg = 'align must be "left", "center" or "right"'
|
||||
raise ValueError(msg)
|
||||
|
||||
for xy, line in lines:
|
||||
bbox_line = self.textbbox(
|
||||
(left, top),
|
||||
xy,
|
||||
line,
|
||||
font,
|
||||
anchor,
|
||||
|
@ -976,8 +969,6 @@ class ImageDraw:
|
|||
max(bbox[3], bbox_line[3]),
|
||||
)
|
||||
|
||||
top += line_spacing
|
||||
|
||||
if bbox is None:
|
||||
return xy[0], xy[1], xy[0], xy[1]
|
||||
return bbox
|
||||
|
|
Loading…
Reference in New Issue
Block a user