How to properly calculate text size in PIL images

José Fernando Costa
Level Up Coding
Published in
3 min readJul 28, 2020

--

PIL is a great package to create and edit images in Python. However, one problem it has is in calculating text size. So today I’m going to show you a short Python script used to draw properly centered text in images created with PIL.

The problem

Unfortunately, the textsize method of the drawing interface does not return the proper text size of a string.

For instance, with this sample code

img = Image.new("RGB", (width, height), color="white")
draw_interface = ImageDraw.Draw(img)
size_width, size_height = draw_interface.textsize("some string", font)

size_width and size_height would return incorrect values.

The solution

So, the solution is to use different calculations for the the text size. Following the solution posted in this Stack Overflow thread (with some changes), the function below is what I ended up with.

Text size calculation

Now let me try to explain the code.

Font metrics
Font metrics (source)

Borrowing the above image from that Stack Overflow thread, I start by getting some font metrics with font.getmetrics. This returns the ascent and descent, that is, according to the PIL documentation

“the distance from the baseline to the highest outline point” and “the distance from the baseline to the lowest outline point, a negative value”

In other words, font.getmetrics returns a tuple with the red and the blue areas of that image, respectively.

The black rectangle is given by font.getmask(text_string).getbox() which returns a four-item tuple: horizontal offset, vertical offset, rectangle’s width and rectangle’s height.

Now that we have the descent and the dimensions of the black rectangle, the height is given by:

font.getmask(text_string).getbox()[3] + descent

And the width by:

font.getmask(text_string).getbox()[2]

This means the height is calculated by summing the height of all the areas in that image and the width is simply the width of the black rectangle.

A practical example

Finally, let’s apply this newfound knowledge to creating an PIL image that has centered text.

Create image with centered text

get_y_and_heights is an adaption of the get_text_dimensions function from the previous code gist. This way the functions returns the vertical coordinate at which to start drawing the text as well as a list of the heights of each text line. And since this new function also returns a list with the heights of each line, I also added the vertical margin to the height calculations. This way, when looping through the text lines to draw them (lines 55 to 65), it’s possible to add the text height to the y variable to find the next vertical coordinate.

The rest of the code is standard code to create a new PIL image and draw text on it.

Resulting image
Resulting image

Conclusion

Hopefully this code if useful for your future work with PIL. All these text metrics are still confusing for me and this not being included in the PIL documentation does not help (namely the getbox function).

At any rate, I think this is a good solution that achieves the objective: to properly calculate the text size of a string drawn with a specific font.

As usual, the code for this article is available on my GitHub repository.

For additional reading, I recommend checking out the “Essential Pil (Pillow) Image Tutorial (for Machine Learning People)” blog post for a thorough introduction to the features of PIL.

--

--