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')