-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
What did you do?
Rendering (multi line) text in left(horizontal) center(vertical) of bounding box.
What did you expect to happen?
Textbox located at left(horizontal), center(vertical)
What actually happened?
Textbox height is wrong. I don't understand line_spacing = self._multiline_spacing(font, spacing, stroke_width) in ImageDraw.multiline_textbbox()
In def multiline_textbbox, self.multiline_spacingfunction
def _multiline_spacing(self, font, spacing, stroke_width):
return (
self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3]
+ stroke_width
+ spacing
)self.textbbox((0, 0), "A", font, stroke_width=stroke_width) is (x1,y1,x2,y2), y1 is not started from zero(In my case, 2), but using (y2+stroke_width+spacing) is not general line_spacing I know.(even "A" is not the highest character!! ex."[", "}" ). line spacing can be different line by line. I suggest
def _multiline_spacing(self, font, spacing, stroke_width):
return (
self.textbbox((0, 0), "[", font, stroke_width=stroke_width)[3]
- self.textbbox((0, 0), "[", font, stroke_width=stroke_width)[1]
+ spacing
)What are your OS, Python and Pillow versions?
- OS: MAC
- Python: 3.9.5
- Pillow:
--------------------------------------------------------------------
Pillow 10.3.0
Python 3.9.5 (default, Nov 23 2021, 15:27:38)
[GCC 9.3.0]
--------------------------------------------------------------------
Python executable is /volume1/ml_image_tr_server/bin/python3
Environment Python files loaded from /volume1/ml_image_tr_server
System Python files loaded from /usr
--------------------------------------------------------------------
Python Pillow modules loaded from /volume1/ml_image_tr_server/lib/python3.9/site-packages/PIL
Binary Pillow modules loaded from /volume1/ml_image_tr_server/lib/python3.9/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 10.3.0
*** TKINTER support not installed
--- FREETYPE2 support ok, loaded 2.13.2
--- LITTLECMS2 support ok, loaded 2.16
--- WEBP support ok, loaded 1.3.2
--- WEBP Transparency support ok
--- WEBPMUX support ok
--- WEBP Animation support ok
--- JPEG support ok, compiled for libjpeg-turbo 3.0.2
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.2
--- ZLIB (PNG/ZIP) support ok, loaded 1.2.11
--- LIBTIFF support ok, loaded 4.6.0
--- RAQM (Bidirectional Text) support ok, loaded 0.10.1, fribidi 1.0.8, harfbuzz 8.4.0
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------
I ignore line spacing, and calculate line height line by line instead of max_line_h(maybe pillow does), and using anchor="lt" (not "la") and adding first y adding stroke_width
from PIL import Image, ImageDraw, ImageFont
import numpy as np
bbox_x1, bbox_y1, bbox_x2, bbox_y2 = 0,0,300,100
bbox_h = bbox_y2 - bbox_y1
text = "Tag[name]\n is \nenglish."
font_size = 20
lang = "english"
writing_direction = "ltr"
text_alignment = "left"
text_border_width=3
canvas_hw=(500, 1000)
text_color=(255, 255, 255)
text_border_color=(125, 125, 125)
font_path = "/volume1/ml_image_tr_server/fonts/Pretendard-Regular.otf" ## your font_path
canvas = Image.new(mode="RGB", size=(canvas_hw[1], canvas_hw[0]))
font = ImageFont.truetype(font=font_path, size=max(1, round(font_size)))
draw = ImageDraw.Draw(canvas)
tx1,ty1,tx2,ty2 = draw.textbbox(
xy=(0, 0),
text=text,
font=font,
anchor=None,
language=lang,
stroke_width=text_border_width,
font_size=font_size
)
lines = text.split('\n')
l_coords = [font.getbbox(
text = line,
language=lang,
stroke_width=text_border_width,
direction = writing_direction
) for line in lines]
total_height = sum([t[3] - t[1] for t in l_coords])
print(f"multi_line tbox y = {ty2-ty1}, total_line_height={total_height}")
start_y = bbox_y1+(bbox_h-total_height)/2 + text_border_width
xy = (bbox_x1+text_border_width, start_y)
anchor = 'lt'
lbox_coords = [] # line box coords
for line_idx, line_text in enumerate(text.split("\n")):
draw.text(
xy = xy,
text = line_text,
fill = text_color,
font = font,
anchor = anchor,
align = text_alignment,
direction = writing_direction,
language=lang,
stroke_width=text_border_width,
stroke_fill = text_border_color
)
lbox_x1, lbox_y1, lbox_x2, lbox_y2 = draw.textbbox(
xy = xy,
text = line_text,
font = font,
anchor = anchor,
align=text_alignment,
direction = writing_direction,
language=lang,
stroke_width=text_border_width,
font_size=font_size
)
# calculate next line xy
xy = (xy[0], xy[1]+(lbox_y2-lbox_y1))
# draw line bbox
draw.rectangle((lbox_x1, lbox_y1, lbox_x2, lbox_y2), outline=(255, 255, 0))
lbox_coords.append([lbox_x1, lbox_y1, lbox_x2, lbox_y2])
lbox_coords = np.array(lbox_coords)
tbox_x1, tbox_y1 = lbox_coords[:, :2].min(axis=0)
tbox_x2, tbox_y2 = lbox_coords[:, 2:4].max(axis=0)
tbox = (tbox_x1, tbox_y1, tbox_x2, tbox_y2)
bbox = (0,0,300,100)
def move_box_a_to_center_of_box_b(A, B):
# A와 B의 좌표 (l, t, r, b)
lA, tA, rA, bA = A
lB, tB, rB, bB = B
# 박스 A의 너비와 높이
width_A = rA - lA
height_A = bA - tA
# 박스 B의 중심 좌표
center_x_B = (lB + rB) / 2
center_y_B = (tB + bB) / 2
# 박스 A의 새로운 좌표 (중심을 B의 중심으로 이동)
new_lA = center_x_B - width_A / 2
new_tA = center_y_B - height_A / 2
new_rA = center_x_B + width_A / 2
new_bA = center_y_B + height_A / 2
# 새로운 A 박스의 좌표 반환
return (new_lA, new_tA, new_rA, new_bA)
ctbox_x1, ctbox_y1, ctbox_x2, ctbox_y2 = move_box_a_to_center_of_box_b(tbox,bbox)
# draw text box and text bbox(bbox center align)
draw.rectangle((ctbox_x1, ctbox_y1, ctbox_x2, ctbox_y2), outline=(255, 0, 255))
draw.rectangle((tbox_x1, tbox_y1, tbox_x2, tbox_y2), outline=(255, 0, 0))
draw.rectangle(bbox, outline=(0,0,255))
canvas.save("result.png")