Skip to content Skip to sidebar Skip to footer

Imagedraw - Adapt Font Size Dynamically To Text Length

The font size has to dynamically adapt to different the text length, which can vary a lot. Currently I have a ton of code, basically manually checking how long the incoming text is

Solution 1:

I don't know other method then ImageDraw.textsize() in for-loop which checks it for different font sizes.

Now I found that in version 8.0.0 they add ImageDraw.textbbox() which gives better results because it calculates also top margin which can be use to better calcualte position.

But it still needs for-loop to check it for different font sizes.


Result with textsize:

enter image description here

Result with textbbox (center vertically):

enter image description here


It is my example which calculate font size and box size to use it directly to calculate

from PIL import Image, ImageDraw, ImageFont

width = 300
height = 100

text = "Hello World"

font_name = 'Ubuntu-M'# --- create image for text ---

img = Image.new('RGB', (width, height), (255, 255, 255))
draw = ImageDraw.Draw(img)

# --- calculate font size, box ---# default values at start
font_size = None# for font size
font = None# for object truetype with correct font size
box = None# for version 8.0.0# test for different font sizesfor size inrange(1, 500):

    # create new font
    new_font = ImageFont.truetype(font_name, size)
    
    # calculate bbox for version 8.0.0
    new_box = draw.textbbox((0, 0), text, new_font)  # need 8.0.0# `bbox` may have top/left margin so calculate real width/height
    new_w = new_box[2] - new_box[0]  # bottom-top
    new_h = new_box[3] - new_box[1]  # right-left#print(size, '|', new_w, new_h, '|', new_box)# if too big then exit with previous valuesif new_w > width or new_h > height:
        break# set new current values as current values
    font_size = size
    font = new_font
    box = new_box
    w = new_w
    h = new_h
    
# --- use it ---print('font size:', font_size)
print('box:', box)

print('w <= width :', w, '<=', width)
print('h <= height:', h, '<=', height)

# calculate position (minus margins in box)
x = (width - w)//2 - box[0]   # minus left margin
y = (height - h)//2 - box[3]  # minus top marginprint('w,h (without margins):', w, h)
print('x,y (without margins):', x, y)

# draw it 
draw.text((x, y), text, (0, 0, 0), font)

# display result
img.show()

img.save('result-textbbox.png', 'png')

EDIT:

The same as function

from PIL import Image, ImageDraw, ImageFont

defget_font(img, text, font_name, width, height):
    # default values at start
    font_size = None# for font size
    font = None# for object truetype with correct font size
    box = None# for version 8.0.0# test for different font sizesfor size inrange(1, 500):

        # create new font
        new_font = ImageFont.truetype(font_name, size)

        # calculate bbox for version 8.0.0
        new_box = draw.textbbox((0, 0), text, new_font)  # need 8.0.0# `bbox` may have top/left margin so calculate real width/height
        new_w = new_box[2] - new_box[0]  # bottom-top
        new_h = new_box[3] - new_box[1]  # right-left#print(size, '|', new_w, new_h, '|', new_box)# if too big then exit with previous valuesif new_w > width or new_h > height:
            break# set new current values as current values
        font_size = size
        font = new_font
        box = new_box
        w = new_w
        h = new_h

        # calculate position (minus margins in box)
        x = (width - w)//2 - box[0]   # minus left margin
        y = (height - h)//2 - box[1]  # minus top marginreturn font, font_size, box, w, h, x, y

# --- main ---

width = 300
height = 100

text = "World"

font_name = 'Ubuntu-M'# --- create image for text ---

img = Image.new('RGB', (width, height), (200, 255, 255))
draw = ImageDraw.Draw(img)

# --- calculate font size, box ---

font, font_size, box, w, h, x, y = get_font(img, text, font_name, width, height)

# --- use it ---print('font size:', font_size)
print('box:', box)

print('w <= width :', w, '<=', width)
print('h <= height:', h, '<=', height)

print('w,h (without margins):', w, h)
print('x,y (without margins):', x, y)

# draw it
draw.text((x, y), text, (0, 0, 0), font)

# display result
img.show()

img.save('result-textbbox.png', 'png')

Post a Comment for "Imagedraw - Adapt Font Size Dynamically To Text Length"