PIL how to scale text size in relation to the size of the image PIL how to scale text size in relation to the size of the image python python

PIL how to scale text size in relation to the size of the image


You could just increment the font size until you find a fit. font.getsize() is the function that tells you how large the rendered text is.

from PIL import ImageFont, ImageDraw, Imageimage = Image.open('hsvwheel.png')draw = ImageDraw.Draw(image)txt = "Hello World"fontsize = 1  # starting font size# portion of image width you want text width to beimg_fraction = 0.50font = ImageFont.truetype("arial.ttf", fontsize)while font.getsize(txt)[0] < img_fraction*image.size[0]:    # iterate until the text size is just larger than the criteria    fontsize += 1    font = ImageFont.truetype("arial.ttf", fontsize)# optionally de-increment to be sure it is less than criteriafontsize -= 1font = ImageFont.truetype("arial.ttf", fontsize)print('final font size',fontsize)draw.text((10, 25), txt, font=font) # put the text on the imageimage.save('hsvwheel_txt.png') # save it

If this is not efficient enough for you, you can implement a root-finding scheme, but I'm guessing that the font.getsize() function is small potatoes compared to the rest of your image editing processes.


In general when you change the font sizing its not going to be a linear change in size of the font.

Non-linear Scaling

Now this often depends on the software, fonts, etc... This example was taken from Typophile and uses LaTex + Computer Modern font. As you can see its not exactly a linear scaling. So if you are having trouble with non-linear font scaling then I'm not sure how to resolve it, but one suggestion maybe is to.

  1. Render the font as closely to the size that you want, then scale that up/down via regular image scaling algorithm...
  2. Just accept that it won't exactly be linear scaling and try to create some sort of table/algorithm that will select the closest point size for the font to match up with the image size.


I know this is an old question that has already been answered with a solution that I too have used. Thanks, @Paul!

Though with increasing the font size by one for each iteration can be time-consuming (at least for me on my poor little server). So eg. small text (like "Foo") would take around 1 - 2 seconds, depending on the image size.

To solve that I adjusted Pauls code so that it searches for the number somewhat like a binary search.

breakpoint = img_fraction * photo.size[0]jumpsize = 75while True:    if font.getsize(text)[0] < breakpoint:        fontsize += jumpsize    else:        jumpsize = jumpsize // 2        fontsize -= jumpsize    font = ImageFont.truetype(font_path, fontsize)    if jumpsize <= 1:        break

Like this, it increases the font size until it's above the breakpoint and from there on out it goes up and down with (cutting the jump size in half with each down) until it has the right size.

With that, I could reduce the steps from around 200+ to about 10 and so from around 1-2 sec to 0.04 to 0.08 sec.

This is a drop-in replacement for Pauls code (for the while statement and the 2 lines after it because you already get the font correct font size in the while)

This was done in a few mins so any improvements are appreciated! I hope this can help some who are looking for a bit more performant friendly solution.