web-dev-qa-db-fra.com

Centrer / centrer le texte avec PIL?

Comment puis-je aligner le texte (et aligner verticalement au milieu) lorsque j'utilise PIL?

49
Phillip B Oldham

Utilisation Draw.textsize méthode pour calculer la taille du texte et recalculer la position en conséquence.

Voici un exemple:

from PIL import Image, ImageDraw

W, H = (300,200)
msg = "hello"

im = Image.new("RGBA",(W,H),"yellow")
draw = ImageDraw.Draw(im)
w, h = draw.textsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, fill="black")

im.save("hello.png", "PNG")

et le résultat:

image with centered text

Si votre taille de police est différente, incluez la police comme ceci:

myFont = ImageFont.truetype("my-font.ttf", 16)
draw.textsize(msg, font=myFont)
102
sastanin

Voici un exemple de code qui utilise textwrap pour diviser une longue ligne en morceaux, puis utilise la méthode textsize pour calculer les positions.

from PIL import Image, ImageDraw, ImageFont
import textwrap

astr = '''The rain in Spain falls mainly on the plains.'''
para = textwrap.wrap(astr, width=15)

MAX_W, MAX_H = 200, 200
im = Image.new('RGB', (MAX_W, MAX_H), (0, 0, 0, 0))
draw = ImageDraw.Draw(im)
font = ImageFont.truetype(
    '/usr/share/fonts/truetype/msttcorefonts/Arial.ttf', 18)

current_h, pad = 50, 10
for line in para:
    w, h = draw.textsize(line, font=font)
    draw.text(((MAX_W - w) / 2, current_h), line, font=font)
    current_h += h + pad

im.save('test.png')

enter image description here

56
unutbu

Il faut noter que la méthode Draw.textsize n'est pas exacte. Je travaillais avec des images à faible pixel, et après quelques tests, il s'est avéré que la taille du texte considère que chaque caractère a une largeur de 6 pixels, alors qu'un "je" prend max. 2 pixels et un "W" prend min. 8 pixels (dans mon cas). Et donc, selon mon texte, il était ou n'était pas du tout centré. Cependant, je suppose que "6" était une moyenne, donc si vous travaillez avec de longs textes et de grandes images, cela devrait quand même être correct.

Mais maintenant, si vous voulez une vraie précision, vous feriez mieux d'utiliser la méthode getsize de l'objet de police que vous allez utiliser:

arial = ImageFont.truetype("arial.ttf", 9)
w,h = arial.getsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, font=arial, fill="black")

Tel qu'utilisé dans le lien d'Edilio.

16
Sindarus

Vous pouvez trouver une implémentation de ceci à http://tools.jedutils.com/tools/center-text-image

Vous pouvez utiliser cette page pour créer l'image là-bas au lieu d'implémenter la routine vous-même, mais le code utilisé est également inclus sur la page.

3
edilio

Les documents PIL pour ImageDraw.text sont un bon point de départ, mais ne répondent pas à votre question.

Vous trouverez ci-dessous un exemple montrant comment centrer le texte dans un cadre de sélection arbitraire, par opposition au centre d'une image. La boîte englobante est définie comme suit: (x1, y1) = coin supérieur gauche et (x2, y2) = coin inférieur droit.

from PIL import Image, ImageDraw, ImageFont

# Create blank rectangle to write on
image = Image.new('RGB', (300, 300), (63, 63, 63, 0))
draw = ImageDraw.Draw(image)

message = 'Stuck in\nthe middle\nwith you'

bounding_box = [20, 30, 110, 160]
x1, y1, x2, y2 = bounding_box  # For easy reading

font = ImageFont.truetype('Consolas.ttf', size=12)

# Calculate the width and height of the text to be drawn, given font size
w, h = draw.textsize(message, font=font)

# Calculate the mid points and offset by the upper left corner of the bounding box
x = (x2 - x1 - w)/2 + x1
y = (y2 - y1 - h)/2 + y1

# Write the text to the image, where (x,y) is the top left corner of the text
draw.text((x, y), message, align='center', font=font)

# Draw the bounding box to show that this works
draw.rectangle([x1, y1, x2, y2])

image.show()
image.save('text_center_multiline.png')

La sortie montre le texte centré verticalement et horizontalement dans le cadre de sélection .

Que vous ayez un message unique ou multiligne n'a plus d'importance, car PIL a incorporé le align='center' paramètre. Cependant, c'est uniquement pour le texte multiligne . Si le message est une seule ligne, il doit être centré manuellement. Si le message est multiligne, align='center' fait le travail pour vous sur les lignes suivantes, mais vous devez toujours centrer manuellement le bloc de texte. Ces deux cas sont résolus à la fois dans le code ci-dessus.

2
aaronpenne

Utilisez la méthode textsize (voir docs ) pour déterminer les dimensions de votre objet texte avant de le dessiner. Ensuite, dessinez-le en commençant aux coordonnées appropriées.

2
Arkady