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
:
Result with textbbox
(center vertically):
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"