I've been through several questions and unsatisfying answers about this. Pillow can use ttf fonts but draw.textsize(text,font) and font.getsize(text) return the same wrong dimensions.
opencv.getTextSize is correct, but only offers a few fonts.
I got precise results by drawing text with pillow on an image dimensioned larger than the approximate size it tells to need, in step 2 converting that image to an opencv pixel array and in step 3 cropping it precisely.
That has two problems:
Is there any chance to get this precise? In the end I'd like to produce boxes quite narrow bounding an inner number (for math related learning/demo video). It's not just to be pedantic, but fiddling with manual corrections would make generating such videos a nightmare, the base tools I now build up should be as precise as possible.
Edit: In my case the texts are numbers, and they neither have ascenders nor descenders. I also observe the horizontal centering works okay, it's just the vertical position is too low. I'll see what I get when taking the offsets into account.
A font has several different metrics, as illustrated by this image from the Pillow appendix on Text Anchors:
The font.getsize() method gives you the size of the text to the ascender line, and not from the top line. If your actual text doesn't include ascenders, that can look like there is too much space.
Pillow 8.0.0 (released a few weeks ago, 2020-10-14) has added methods that address these issues, at least for TypeFont fonts, and you really want to use the new ImageDraw.textbbox() or FreeTypeFont.getbbox() methods, with the anchor set to 'lt' (left, top). The former transposes the result of the latter to the chosen (x, y) coordinates.
The documentation for FreeTypeFont.getsize() has been updated to add a note to this effect:
For historical reasons this function measures text height from the ascender line instead of the top, see Text anchors. If you wish to measure text height from the top, it is recommended to use the bottom value of
getbbox()withanchor='lt'instead.
You may also be interested in one of the issues that were addressed by these new API additions, where the developer that added these methods demonstrates that ImageDraw.getbbox() can be used to get exact bounding boxes per character in a given text.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With