Wie würde ich Text bei Verwendung von PIL mittig ausrichten (und mittig vertikal ausrichten)?
Wie würde ich Text bei Verwendung von PIL mittig ausrichten (und mittig vertikal ausrichten)?
Antworten:
Verwenden Sie die Draw.textsize
Methode , um die Textgröße zu berechnen und die Position entsprechend neu zu berechnen.
Hier ist ein Beispiel:
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")
und das Ergebnis:
Wenn Ihre Schriftgröße unterschiedlich ist, geben Sie die folgende Schriftart an:
myFont = ImageFont.truetype("my-font.ttf", 16)
draw.textsize(msg, font=myFont)
draw.textsize(msg, font=myFont)
folgt einzuschließen : Andernfalls wird sie nicht richtig zentriert
Hier ist ein Beispielcode, der Textwrap verwendet, um eine lange Zeile in Teile zu teilen, und dann die textsize
Methode verwendet, um die Positionen zu berechnen.
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')
width
Zeichen zählt, während PIL-Bilder in Pixel messen. Ich habe eine Version des oben genannten verwendet, aber vor der for-Schleife, die die Zeilen schreibt, eine while-Schleife hinzugefügt. Zuerst habe ich eine beliebig hohe Zeichenanzahl festgelegt, um zu beginnen, dann habe ich Textwrap verwendet, um die Linien zu brechen, und dann habe ich .textsize verwendet, um die Pixelbreite der ersten Ausgabe in der Textwrap-Ergebnisliste zu messen. Wenn es passt, fahren Sie fort, andernfalls verringern Sie meine Zeichenanzahl und messen Sie erneut, bis die Linien zum Bild passen.
Man muss beachten, dass die Draw.textsize
Methode ungenau ist. Ich habe mit Bildern mit niedrigen Pixeln gearbeitet, und nach einigen Tests stellte sich heraus, dass textsize
jedes Zeichen 6 Pixel breit ist, während ein Zeichen I
max. 2 Pixel und a W
dauert min. 8 Pixel (in meinem Fall). Und so war es, abhängig von meinem Text, überhaupt nicht zentriert. Ich denke, "6" war ein Durchschnitt. Wenn Sie also mit langen Texten und großen Bildern arbeiten, sollte es immer noch in Ordnung sein.
Wenn Sie jedoch eine echte Genauigkeit wünschen, verwenden Sie besser die getsize
Methode des Schriftobjekts, das Sie verwenden möchten :
arial = ImageFont.truetype("arial.ttf", 9)
w,h = arial.getsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, font=arial, fill="black")
Wie in Edilios Link verwendet.
getsize
akzeptiert nicht-lateinische Zeichen wie € oder deutsche Umlaute. textsize
nicht. ThumbsUp :-)
Die PIL-Dokumente für ImageDraw.text sind ein guter Anfang, aber beantworten Sie Ihre Frage nicht.
Im Folgenden finden Sie ein Beispiel für das Zentrieren des Texts in einem beliebigen Begrenzungsrahmen im Gegensatz zur Bildmitte. Der Begrenzungsrahmen ist definiert als: (x1, y1)
= obere linke Ecke und (x2, y2)
= untere rechte Ecke.
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')
Die Ausgabe zeigt den vertikal und horizontal zentrierten Text im Begrenzungsrahmen .
Ob Sie eine ein- oder mehrzeilige Nachricht haben, spielt keine Rolle mehr, da PIL den align='center'
Parameter integriert hat. Dies gilt jedoch nur für mehrzeiligen Text . Wenn die Nachricht eine einzelne Zeile ist, muss sie manuell zentriert werden. Wenn die Nachricht mehrzeilig ist, align='center'
erledigt sie die Arbeit für Sie in nachfolgenden Zeilen, aber Sie müssen den Textblock trotzdem manuell zentrieren. Beide Fälle werden im obigen Code sofort gelöst.