mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-11 09:00:59 +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
|
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(
|
def text(
|
||||||
self,
|
self,
|
||||||
xy: tuple[float, float],
|
xy: tuple[float, float],
|
||||||
|
@ -697,6 +682,101 @@ class ImageDraw:
|
||||||
# Only draw normal text
|
# Only draw normal text
|
||||||
draw_text(ink)
|
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(
|
def multiline_text(
|
||||||
self,
|
self,
|
||||||
xy: tuple[float, float],
|
xy: tuple[float, float],
|
||||||
|
@ -720,67 +800,24 @@ class ImageDraw:
|
||||||
*,
|
*,
|
||||||
font_size: float | None = None,
|
font_size: float | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if direction == "ttb":
|
font, anchor, lines = self._prepare_multiline_text(
|
||||||
msg = "ttb direction is unsupported for multiline text"
|
xy,
|
||||||
raise ValueError(msg)
|
text,
|
||||||
|
|
||||||
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,
|
font,
|
||||||
direction=direction,
|
anchor,
|
||||||
features=features,
|
spacing,
|
||||||
language=language,
|
align,
|
||||||
embedded_color=embedded_color,
|
direction,
|
||||||
|
features,
|
||||||
|
language,
|
||||||
|
stroke_width,
|
||||||
|
embedded_color,
|
||||||
|
font_size,
|
||||||
)
|
)
|
||||||
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)
|
|
||||||
|
|
||||||
|
for xy, line in lines:
|
||||||
self.text(
|
self.text(
|
||||||
(left, top),
|
xy,
|
||||||
line,
|
line,
|
||||||
fill,
|
fill,
|
||||||
font,
|
font,
|
||||||
|
@ -792,7 +829,6 @@ class ImageDraw:
|
||||||
stroke_fill=stroke_fill,
|
stroke_fill=stroke_fill,
|
||||||
embedded_color=embedded_color,
|
embedded_color=embedded_color,
|
||||||
)
|
)
|
||||||
top += line_spacing
|
|
||||||
|
|
||||||
def textlength(
|
def textlength(
|
||||||
self,
|
self,
|
||||||
|
@ -894,69 +930,26 @@ class ImageDraw:
|
||||||
*,
|
*,
|
||||||
font_size: float | None = None,
|
font_size: float | None = None,
|
||||||
) -> tuple[float, float, float, float]:
|
) -> tuple[float, float, float, float]:
|
||||||
if direction == "ttb":
|
font, anchor, lines = self._prepare_multiline_text(
|
||||||
msg = "ttb direction is unsupported for multiline text"
|
xy,
|
||||||
raise ValueError(msg)
|
text,
|
||||||
|
|
||||||
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,
|
font,
|
||||||
direction=direction,
|
anchor,
|
||||||
features=features,
|
spacing,
|
||||||
language=language,
|
align,
|
||||||
embedded_color=embedded_color,
|
direction,
|
||||||
|
features,
|
||||||
|
language,
|
||||||
|
stroke_width,
|
||||||
|
embedded_color,
|
||||||
|
font_size,
|
||||||
)
|
)
|
||||||
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
|
|
||||||
|
|
||||||
bbox: tuple[float, float, float, float] | None = None
|
bbox: tuple[float, float, float, float] | None = None
|
||||||
|
|
||||||
for idx, line in enumerate(lines):
|
for xy, line in 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)
|
|
||||||
|
|
||||||
bbox_line = self.textbbox(
|
bbox_line = self.textbbox(
|
||||||
(left, top),
|
xy,
|
||||||
line,
|
line,
|
||||||
font,
|
font,
|
||||||
anchor,
|
anchor,
|
||||||
|
@ -976,8 +969,6 @@ class ImageDraw:
|
||||||
max(bbox[3], bbox_line[3]),
|
max(bbox[3], bbox_line[3]),
|
||||||
)
|
)
|
||||||
|
|
||||||
top += line_spacing
|
|
||||||
|
|
||||||
if bbox is None:
|
if bbox is None:
|
||||||
return xy[0], xy[1], xy[0], xy[1]
|
return xy[0], xy[1], xy[0], xy[1]
|
||||||
return bbox
|
return bbox
|
||||||
|
|
Loading…
Reference in New Issue
Block a user