问题
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 and manually giving a font size for that.
There has to be a better solution. I don't think I can use ImageDraw.textsize.
Has anyone a solution for this kinda problem?
Thanks
回答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 sizes
for size in range(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 values
if 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 margin
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')
EDIT:
The same as function
from PIL import Image, ImageDraw, ImageFont
def get_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 sizes
for size in range(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 values
if 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 margin
return 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')
来源:https://stackoverflow.com/questions/65494932/imagedraw-adapt-font-size-dynamically-to-text-length