python ImageDraw -根据文本长度动态调整字体大小

ivqmmu1c  于 2023-02-07  发布在  Python
关注(0)|答案(1)|浏览(979)

字体大小必须动态地适应不同的文本长度,这可能会有很大的变化。目前我有大量的代码,基本上是手动检查传入的文本有多长,并手动给出字体大小。
必须有更好的解决方案。我不认为我可以使用ImageDraw.textsize
有人能解决这类问题吗?

5jdjgkvh

5jdjgkvh1#

除了for循环中的ImageDraw.textsize()之外,我不知道还有其他方法可以检查不同的字体大小。
现在我发现在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')

相关问题