Measuring width of text (Python/PIL)

Kerning

You’re doing two different things here:

  • Find the width of a long text.
  • Find the width of all the characters, and blindly adding them together

If you were using a monospace font, things might be different, but fonts generally use something called kerning to make the text smoother and a bit tighter.

Wikipedia says:

In typography, kerning is the process of adjusting the spacing between characters in a proportional font, usually to achieve a visually pleasing result. Kerning adjusts the space between individual letter forms, while tracking (letter-spacing) adjusts spacing uniformly over a range of characters. In a well-kerned font, the two-dimensional blank spaces between each pair of characters all have a visually similar area.

Kerning brings A and V closer with their serifs over each other

Here’s some kerning of the DejaVuSans font:

font kerning showing different char widths

Under the hood

Under the hood, Pillow isn’t doing much different for your two methods. It’s just you’re calling them in different ways.

If you add a third method to get the width of the whole sentence using the same function as in method two, you’ll also get the same width as getting the whole sentence as in method one:

# METHOD 3
width = font.getsize(sample)[0]
print width

Here’s Pillow’s ImageDraw.textsize (from methods one and three):

def textsize(self, text, font=None, *args, **kwargs):
    """Get the size of a given string, in pixels."""
    if self._multiline_check(text):
        return self.multiline_textsize(text, font, *args, **kwargs)

    if font is None:
        font = self.getfont()
    return font.getsize(text)

For single-line text, this is just returning the font.getsize, the same as method two. (And for multiline text, it just splits it into lines and returns the sum of several font.getsize calls.)

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)