Pillow, how to put the text in the center of the image

Solution 1:

Text always have some added space around characters, e.g. if we create a box that is the exact size reported for your 'H'

img = Image.new("L", (width, height), color=0)   # "L": (8-bit pixels, black and white)
font = ImageFont.truetype("arial.ttf", font_size)
draw = ImageDraw.Draw(img)
w, h = draw.textsize(text, font=font)
# draw.text(((width-w)/2, (height-h)/2), text=text, fill='white', font=font)
# img.save('H.png')
img2 = Image.new("L", (w, h), color=0)   # "L": (8-bit pixels, black and white)
draw2 = ImageDraw.Draw(img2)
draw2.text((0, 0)), text=text, fill='white', font=font)
img2.save('H.png')

gives the bounding box:

enter image description here

Knowing that line height is normally ~20% larger than the glyphs/characters (+ some trial and error), and we can figure out the extent of the extra space. (The extra space for width is equally distributed so not interesting for centering).

draw2.text((0, 0 - int(h*0.21)), text=text, fill='white', font=font)

which moves the 'H' to the top:

enter image description here

Plugging this back into your original code:

img = Image.new("L", (width, height), color=0)   # "L": (8-bit pixels, black and white)
font = ImageFont.truetype("arial.ttf", font_size)
draw = ImageDraw.Draw(img)
w, h = draw.textsize(text, font=font)
h += int(h*0.21)
draw.text(((width-w)/2, (height-h)/2), text=text, fill='white', font=font)
img.save('H.png')

gives:

enter image description here

The 0.21 factor usually works well for a large range of font sizes for the same font. E.g. just plugging in font size 30:

enter image description here