J'essaie d'ajouter du texte au bas de l'image et je l'ai fait, mais si mon texte est plus long que la largeur de l'image, il est coupé des deux côtés. Pour simplifier, j'aimerais que le texte soit composé de plusieurs lignes s'il est plus long que la largeur de l'image. Voici mon code:
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')
Vous pouvez utiliser textwrap.wrap
pour séparer text
en une liste de chaînes de caractères contenant au plus width
caractères:
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
La réponse acceptée englobe le texte sans mesurer la police (40 caractères maximum, quelles que soient la taille de la police et la largeur de la boîte), de sorte que les résultats ne sont qu'approximatifs et peuvent facilement remplir ou sous-remplir la zone.
Voici une bibliothèque simple qui résout le problème correctement: https://Gist.github.com/turicas/1455973
Toutes les recommandations sur l'utilisation de textwrap
ne permettent pas de déterminer la largeur correcte des polices non monospaces (comme Arial, utilisée dans l'exemple de code de la rubrique).
J'ai écrit une classe d'assistance simple pour envelopper le texte concernant le redimensionnement des lettres de police réelles:
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)
Exemple d'utilisation:
wrapper = TextWrapper(text, image_font_intance, 800)
wrapped_text = wrapper.wrapped_text()
Ce n'est probablement pas très rapide, car il rend le texte entier Word par Word, afin de déterminer la largeur des mots. Mais dans la plupart des cas, ça devrait aller.