recognition - python PIL dibuja texto multilínea en la imagen
pillow python (5)
La respuesta aceptada envuelve el texto sin medir la fuente (máximo 40 caracteres, sin importar el tamaño de la fuente y el ancho de la caja), por lo que los resultados son solo aproximados y pueden sobrellenar o llenar poco la casilla.
Aquí hay una biblioteca simple que resuelve el problema correctamente: https://gist.github.com/turicas/1455973
Intento agregar texto en la parte inferior de la imagen y en realidad lo he hecho, pero en caso de que mi texto sea más largo, el ancho de la imagen se corta por ambos lados, para simplificar. Me gustaría que el texto estuviera en varias líneas si es más largo que el ancho de la imagen. Aquí está mi código:
FOREGROUND = (255, 255, 255)
WIDTH = 375
HEIGHT = 50
TEXT = ''Chyba najwyższy czas zadać to pytanie na śniadanie /n Chyba najwyższy czas zadać to pytanie na śniadanie''
font_path = ''/Library/Fonts/Arial.ttf''
font = ImageFont.truetype(font_path, 14, encoding=''unic'')
text = TEXT.decode(''utf-8'')
(width, height) = font.getsize(text)
x = Image.open(''media/converty/image.png'')
y = ImageOps.expand(x,border=2,fill=''white'')
y = ImageOps.expand(y,border=30,fill=''black'')
w, h = y.size
bg = Image.new(''RGBA'', (w, 1000), "#000000")
W, H = bg.size
xo, yo = (W-w)/2, (H-h)/2
bg.paste(y, (xo, 0, xo+w, h))
draw = ImageDraw.Draw(bg)
draw.text(((w - width)/2, w), text, font=font, fill=FOREGROUND)
bg.show()
bg.save(''media/converty/test.png'')
Podría usar PIL.ImageDraw.Draw.multiline_text()
.
draw.multiline_text((WIDTH, HEIGHT), TEXT, fill=FOREGROUND, font=font)
Incluso establece spacing
o align
con los mismos nombres de param.
Puede usar textwrap.wrap
para dividir el text
en una lista de cadenas, cada una con la mayor cantidad de caracteres de width
:
import textwrap
lines = textwrap.wrap(text, width=40)
y_text = h
for line in lines:
width, height = font.getsize(line)
draw.text(((w - width) / 2, y_text), line, font=font, fill=FOREGROUND)
y_text += height
Todas las recomendaciones sobre el uso de textwrap
no determinan el ancho correcto para fuentes no monoespaciadas (como Arial, que se usa en el código de ejemplo de tema).
Escribí una clase de ayuda simple para ajustar el texto con respecto al tamaño real de las letras de las fuentes:
class TextWrapper(object):
""" Helper class to wrap text in lines, based on given text, font
and max allowed line width.
"""
def __init__(self, text, font, max_width):
self.text = text
self.text_lines = [
'' ''.join([w.strip() for w in l.split('' '') if w])
for l in text.split(''/n'')
if l
]
self.font = font
self.max_width = max_width
self.draw = ImageDraw.Draw(
Image.new(
mode=''RGB'',
size=(100, 100)
)
)
self.space_width = self.draw.textsize(
text='' '',
font=self.font
)[0]
def get_text_width(self, text):
return self.draw.textsize(
text=text,
font=self.font
)[0]
def wrapped_text(self):
wrapped_lines = []
buf = []
buf_width = 0
for line in self.text_lines:
for word in line.split('' ''):
word_width = self.get_text_width(word)
expected_width = word_width if not buf else /
buf_width + self.space_width + word_width
if expected_width <= self.max_width:
# word fits in line
buf_width = expected_width
buf.append(word)
else:
# word doesn''t fit in line
wrapped_lines.append('' ''.join(buf))
buf = [word]
buf_width = word_width
if buf:
wrapped_lines.append('' ''.join(buf))
buf = []
buf_width = 0
return ''/n''.join(wrapped_lines)
Ejemplo de uso:
wrapper = TextWrapper(text, image_font_intance, 800)
wrapped_text = wrapper.wrapped_text()
Probablemente no sea súper rápido, ya que procesa el texto completo palabra por palabra para determinar el ancho de las palabras. Pero para la mayoría de los casos, debería estar bien.
text = textwrap.fill("test ",width=35)
self.draw.text((x, y), text, font=font, fill="Black")