ImageDraw - 动态调整字体大小以适应文本长度
ImageDraw - adapt Font Size dynamically to text length
字体大小必须动态适应不同的文本长度,这可能会有很大差异。
目前我有大量代码,基本上是手动检查传入文本的长度并手动为其指定字体大小。
必须有更好的解决方案。我不认为我可以使用 ImageDraw.textsize.
有人能解决这个问题吗?
谢谢
我不知道 ImageDraw.textsize()
在 for
循环中检查不同字体大小的其他方法。
现在我发现在 8.0.0 版中他们添加了 ImageDraw.textbbox()
,这提供了更好的结果,因为它还计算了可用于更好地计算位置的顶部边距。
但它仍然需要 for
-loop 来检查不同的字体大小。
结果 textsize
:
textbbox
的结果(垂直居中):
我的例子是计算字体大小和框大小直接用它来计算
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')
编辑:
同函数
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')
字体大小必须动态适应不同的文本长度,这可能会有很大差异。 目前我有大量代码,基本上是手动检查传入文本的长度并手动为其指定字体大小。
必须有更好的解决方案。我不认为我可以使用 ImageDraw.textsize.
有人能解决这个问题吗?
谢谢
我不知道 ImageDraw.textsize()
在 for
循环中检查不同字体大小的其他方法。
现在我发现在 8.0.0 版中他们添加了 ImageDraw.textbbox()
,这提供了更好的结果,因为它还计算了可用于更好地计算位置的顶部边距。
但它仍然需要 for
-loop 来检查不同的字体大小。
结果 textsize
:
textbbox
的结果(垂直居中):
我的例子是计算字体大小和框大小直接用它来计算
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')
编辑:
同函数
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')