limitations of python text wrapper – a modest workaround

Writting text on image using TextWrap and PIL seems easy at first sight…but some users are suffering to know exactly what will be the dimensions of the wrap. There are  2 problems : 

carlim

This takes carlim in parameters and not the desired dimension of the box.

fontsize

This may give a bad estimation when you use a custom font.
I describe in this post my solution to tackle these two problems.

For the livemapping project I wanted to find the biggest font size to print a  text on a limited square. I wanted to generate programmatically  some new images with a custom text. For example :welcome

Problem of carLim and FontSize optimization

The problem is more complicated that I first thought, because a (1) a bigger Font Size means a fewer carlim limit in order to not exceed Width and (2) a fewer carlim limit implies that the text may be split in many lines, exceeding Height. In a more formal way,  a text being given, we want to find the best {carlim , FontSize} for a desired dimension {Width , Height}. Maybe there is an analytic solution, I did not find it, but if someone has the answer, I would be pleased to erase this post and write a best solution instead.welcome2

The path I chose is classic in optimization problems : trying  to optimize FontSize and carlimMax step by step. Note that In my first trials, I encountered some nasty cyclic behavior : FontSize get really big, and carlim very small, then the opposite, then again the opposite etc… that’s why you will see in my script two different functions “nonconservative” and “conservative” (which mean current values with t-1 step values) in order to avoid  cyclic behaviors.

To use the what I wrote,  you can simply import the module superWrapper.py , and call

to know the font size and the carlim to use.
If your text is supposed to be displayed in only one line, you have to use rather :

If you don’t know  by advance if your text will be in one line or more you can use a condition to make your choice like the (empirical) one I use :

 

Problem of true metrics

draw.text is often deceiving as it prints sometimes something bigger or smaller, but more importantly display the text outside the desired box. The problem seems to be more critical when small texts are to be printed. If I understood well, it comes from the custom font for which metrics are not well specified, and it seems that it’s possible to change this using fontforge.

I found my answer on stackOverflow, I wanted to give the link, but I don’t find it anymore. The solution was to print text on a black background and use getbbox on the generated image to get the exact position and dimensions of the textBox.

Example for centering a text on an image (a font and an image being given)

If you have some suggestions or a better workaround, please tell me !
Python script :  superWrapper.py