djscanlation / add_text.py
maggidev's picture
Update add_text.py
7981cc4 verified
import cv2
import textwrap
from PIL import Image, ImageDraw, ImageFont
import numpy as np
def add_text(
image,
text,
contour,
font_path,
initial_font_size=42,
padding=10,
line_spacing=1.25
):
"""
Renderiza texto dentro de uma bolha usando o CONTOUR como referência.
Prioriza quebra de linhas antes de reduzir a fonte.
"""
# --- Extrai bounding box do contorno ---
x, y, w, h = cv2.boundingRect(contour)
img_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
font_size = initial_font_size
wrapping_ratio = 0.9
while font_size > 10:
font = ImageFont.truetype(font_path, font_size)
max_chars_per_line = max(
1, int((w - 2 * padding) / (font_size * wrapping_ratio))
)
lines = textwrap.wrap(text, width=max_chars_per_line)
# Evita linha única quando há espaço vertical
min_lines = 2 if h > font_size * 2.5 else 1
if len(lines) < min_lines:
wrapping_ratio -= 0.03
continue
max_line_width = 0
total_height = 0
for line in lines:
bbox_text = draw.textbbox((0, 0), line, font=font)
lw = bbox_text[2] - bbox_text[0]
lh = bbox_text[3] - bbox_text[1]
max_line_width = max(max_line_width, lw)
total_height += lh
total_height = int(total_height * line_spacing)
if (
total_height <= (h - 2 * padding)
and max_line_width <= (w - 2 * padding)
):
break
if max_line_width > (w - 2 * padding):
wrapping_ratio -= 0.02
else:
font_size -= 1
# --- Centralização ---
current_y = y + padding + (h - total_height) // 2
for line in lines:
bbox_text = draw.textbbox((0, 0), line, font=font)
lw = bbox_text[2] - bbox_text[0]
lh = bbox_text[3] - bbox_text[1]
text_x = x + (w - lw) // 2
draw.text((text_x, current_y), line, fill=(0, 0, 0), font=font)
current_y += int(lh * line_spacing)
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)