如何用PIL实现文本居中对齐?

122 投票
11 回答
109411 浏览
提问于 2025-04-15 17:26

我该如何在使用PIL时让文字居中对齐(并且垂直居中)呢?

11 个回答

39

需要注意的是,Draw.textsize 这个方法并不准确。我在处理低像素的图片时,经过一些测试发现,textsize 认为每个字符都是6个像素宽,但实际上一个 I 字母最多只占2个像素,而一个 W 字母最少占8个像素(在我的情况下)。所以,根据我输入的文本,有时候它根本没有居中。不过,我想“6”可能是个平均值,所以如果你处理的是长文本和大图片,应该还是可以的。

但是,如果你想要真正准确的结果,最好使用你要用的字体对象的 getsize 方法:

arial = ImageFont.truetype("arial.ttf", 9)
w,h = arial.getsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, font=arial, fill="black")

就像在Edilio的链接中使用的那样。

88

这里有一段示例代码,它使用了textwrap这个工具来把一行很长的文字分成几段,然后用textsize这个方法来计算每段文字的位置。

from PIL import Image, ImageDraw, ImageFont
import textwrap

astr = '''The rain in Spain falls mainly on the plains.'''
para = textwrap.wrap(astr, width=15)

MAX_W, MAX_H = 200, 200
im = Image.new('RGB', (MAX_W, MAX_H), (0, 0, 0, 0))
draw = ImageDraw.Draw(im)
font = ImageFont.truetype(
    '/usr/share/fonts/truetype/msttcorefonts/Arial.ttf', 18)

current_h, pad = 50, 10
for line in para:
    w, h = draw.textsize(line, font=font)
    draw.text(((MAX_W - w) / 2, current_h), line, font=font)
    current_h += h + pad

im.save('test.png')

在这里输入图片描述

222

弃用警告: textsize 这个功能已经被弃用,并将在 Pillow 10 版本中移除(2023-07-01)。请使用 textbbox 或 textlength 来代替。

使用 textbbox 来替代 textsize 的代码。

from PIL import Image, ImageDraw, ImageFont


def create_image(size, bgColor, message, font, fontColor):
    W, H = size
    image = Image.new('RGB', size, bgColor)
    draw = ImageDraw.Draw(image)
    _, _, w, h = draw.textbbox((0, 0), message, font=font)
    draw.text(((W-w)/2, (H-h)/2), message, font=font, fill=fontColor)
    return image
myFont = ImageFont.truetype('Roboto-Regular.ttf', 16)
myMessage = 'Hello World'
myImage = create_image((300, 200), 'yellow', myMessage, myFont, 'black')
myImage.save('hello_world.png', "PNG")

结果

结果


使用 Draw.textsize 方法 来计算文本的大小,并相应地重新计算位置。

这里有一个例子:

from PIL import Image, ImageDraw

W, H = (300,200)
msg = "hello"

im = Image.new("RGBA",(W,H),"yellow")
draw = ImageDraw.Draw(im)
w, h = draw.textsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, fill="black")

im.save("hello.png", "PNG")

以及结果:

带有居中文本的图片

如果你的字体大小不同,可以像这样包含字体:

myFont = ImageFont.truetype("my-font.ttf", 16)
draw.textsize(msg, font=myFont)

撰写回答