Johnny
Johnny

Reputation: 173

horizontally and vertically align of text with PIL

I have a string (a sentence) thats approximately 100 characters long and with this example code (it uses textwrap) I can split the string into pieces, and then compute the positions with the textsize method:

import Image
import ImageDraw
import ImageFont
import textwrap

sentence='This is a text. Some more text 123. Align me please.'
para=textwrap.wrap(sentence,width=15)

MAX_W,MAX_H=500,800
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', 36)

current_h=0
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

im.save('test.png')

This code is align the text horizontally, but I need the text to be vertically aligned too. How can I do this? The dimensions of my image are 800x500 and I just want to fit a 100 characters long text the perfect way. Maybe I should calculate everything over pixel?

Upvotes: 2

Views: 2854

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121884

You need to take into account that the height of the text is going to be used for every line of text; calculate the vertical size for all lines and base your positions on that:

# Half of the remainder of the image height when space for all lines has been reserved:
line_dimensions = [draw.textsize(line, font=font) for line in para]
offset = (MAX_H - sum(h for w, h in line_dimensions)) // 2

current_h = offset
for line, (w, h) in zip(para, line_dimensions):
    draw.text(((MAX_W - w) // 2, current_h), line, font=font)
    current_h += h

Here line_dimensions is a list of (width, height) tuples for each line in the paragraph. The total height is then taken from that (with the sum() and generator expression), and we use that to calculate an initial offset.

Upvotes: 3

Related Questions