Despite other answers saying that font size do not scale linearly, in all the examples that I tested they did scale linearly (within 1-2%).
So if you need a simpler and more efficient version that works within a few percent, you can copy/paste the following:
from PIL import ImageFont, ImageDraw, Image
def find_font_size(text, font, image, target_width_ratio):
tested_font_size = 100
tested_font = ImageFont.truetype(font, tested_font_size)
observed_width, observed_height = get_text_size(text, image, tested_font)
estimated_font_size = tested_font_size / (observed_width / image.width) * target_width_ratio
return round(estimated_font_size)
def get_text_size(text, image, font):
im = Image.new('RGB', (image.width, image.height))
draw = ImageDraw.Draw(im)
return draw.textsize(text, font)
The function find_font_size()
can then be used like that (full example):
width_ratio = 0.5 # Portion of the image the text width should be (between 0 and 1)
font_family = "arial.ttf"
text = "Hello World"
image = Image.open('image.jpg')
editable_image = ImageDraw.Draw(image)
font_size = find_font_size(text, font_family, image, width_ratio)
font = ImageFont.truetype(font_family, font_size)
print(f"Font size found = {font_size} - Target ratio = {width_ratio} - Measured ratio = {get_text_size(text, image, font)[0] / image.width}")
editable_image.text((10, 10), text, font=font)
image.save('output.png')
Which for a 225x225 image would print:
>> Font size found = 22 - Target ratio = 0.5 - Measured ratio = 0.502
I tested find_font_size()
with various fonts and picture sizes, and it worked in all cases.
If you want to know how this function works, basically tested_font_size
is used to find out which ratio will be obtained if we use this specific font size to generate the text. Then, we use a cross-multiplication rule to get the targeted font size.
I tested different values for tested_font_size
and found that as long as it's not too small, it does not make any difference.
OSError: cannot open resource
. Do I have to first download the font from somewhere? – Joanjoana