Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I use the Pillow (PIL) 6.0 and add text in the image. And I want to put the text in the center of the image. Here is my code,

import os
import string
from PIL import Image
from PIL import ImageFont, ImageDraw, ImageOps

width, height = 100, 100

text = 'H'
font_size = 100

os.makedirs('./{}'.format(text), exist_ok=True)

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')

Here is the output:

enter image description here

Question:

The text is in the center horizontally, but not in the center vertically. How can I put it in the center horizontally and vertically?

like image 743
qinlong Avatar asked Apr 20 '19 13:04

qinlong


People also ask

How do I align text to the center of an image?

To center an image using text-align: center; you must place the <img> inside of a block-level element such as a div . Since the text-align property only applies to block-level elements, you place text-align: center; on the wrapping block-level element to achieve a horizontally centered <img> .

How do I bring text to the center?

Select the text that you want to center. in the Page Setup group, and then click the Layout tab. In the Vertical alignment box, click Center. In the Apply to box, click Selected text, and then click OK.

What is a horizontal anchor typography?

Horizontal anchor alignmentAnchor is to the left of the text. For horizontal text this is the origin of the first glyph, as shown in the FreeType tutorial. m — middle. Anchor is horizontally centered with the text.


1 Answers

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

like image 136
thebjorn Avatar answered Oct 09 '22 22:10

thebjorn