使用PIL进行中心/中间对齐文本?

时间:2009-12-28 18:21:20

标签: python python-imaging-library

使用PIL时,我如何居中对齐(和中间垂直对齐)文本?

7 个答案:

答案 0 :(得分:96)

使用Draw.textsize method计算文字大小并相应地重新计算位置。

以下是一个例子:

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

结果:

image with centered text

如果您的字体大小不同,请包含以下字体:

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

答案 1 :(得分:56)

下面是一些示例代码,它使用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')

enter image description here

答案 2 :(得分:16)

应该注意Draw.textsize方法是不准确的。我正在使用低像素图像,经过一些测试,结果发现textize认为每个字符都是6像素宽,而#34; 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的链接。

答案 3 :(得分:6)

如果您使用的是 PIL 8.0.0 或更高版本,一个简单的解决方案:text anchors

width, height = # image width and height
draw = ImageDraw.draw(my_image)

draw.text((width/2, height/2), "my text", font=my_font, anchor="mm")

mm 表示使用文本的中间作为锚点,水平和垂直。

有关其他类型的锚定,请参阅锚定页面。例如,如果您只想水平居中,您可能需要使用 ma

答案 4 :(得分:3)

您可以在http://tools.jedutils.com/tools/center-text-image

找到此实现

您可以使用该页面在那里创建图像,而不是自己实现例程,但使用的代码也包含在页面中。

答案 5 :(得分:2)

在实际绘制文本对象之前,使用textsize方法(请参阅docs)确定文本对象的尺寸。然后从适当的坐标开始绘制它。

答案 6 :(得分:1)

PIL docs for ImageDraw.text是一个很好的起点,但不回答你的问题。

下面是如何将文本居中于任意边界框的示例,而不是图像的中心。边界框的定义为:(x1, y1) =左上角和(x2, y2) =右下角。

from PIL import Image, ImageDraw, ImageFont

# Create blank rectangle to write on
image = Image.new('RGB', (300, 300), (63, 63, 63, 0))
draw = ImageDraw.Draw(image)

message = 'Stuck in\nthe middle\nwith you'

bounding_box = [20, 30, 110, 160]
x1, y1, x2, y2 = bounding_box  # For easy reading

font = ImageFont.truetype('Consolas.ttf', size=12)

# Calculate the width and height of the text to be drawn, given font size
w, h = draw.textsize(message, font=font)

# Calculate the mid points and offset by the upper left corner of the bounding box
x = (x2 - x1 - w)/2 + x1
y = (y2 - y1 - h)/2 + y1

# Write the text to the image, where (x,y) is the top left corner of the text
draw.text((x, y), message, align='center', font=font)

# Draw the bounding box to show that this works
draw.rectangle([x1, y1, x2, y2])

image.show()
image.save('text_center_multiline.png')

The output shows the text centered vertically and horizontally in the bounding box

由于PIL包含align='center'参数,因此单行或多行消息不再重要。但是,它仅用于多行文字。如果消息是单行,则需要手动居中。如果邮件是多行的,align='center'会在后续行中为您工作,但您仍需要手动居中文本块。在上面的代码中,这两种情况都可以立即解决。