PIL - 在图像上绘制多行文本
我试着在图片底部添加文字,实际上我已经做到了。但如果我的文字比图片宽度还长,就会被从两边截断。为了简单起见,我希望如果文字超过图片宽度,就能换行显示。以下是我的代码:
FOREGROUND = (255, 255, 255)
WIDTH = 375
HEIGHT = 50
TEXT = 'Chyba najwyższy czas zadać to pytanie na śniadanie \n Chyba najwyższy czas zadać to pytanie na śniadanie'
font_path = '/Library/Fonts/Arial.ttf'
font = ImageFont.truetype(font_path, 14, encoding='unic')
text = TEXT.decode('utf-8')
(width, height) = font.getsize(text)
x = Image.open('media/converty/image.png')
y = ImageOps.expand(x,border=2,fill='white')
y = ImageOps.expand(y,border=30,fill='black')
w, h = y.size
bg = Image.new('RGBA', (w, 1000), "#000000")
W, H = bg.size
xo, yo = (W-w)/2, (H-h)/2
bg.paste(y, (xo, 0, xo+w, h))
draw = ImageDraw.Draw(bg)
draw.text(((w - width)/2, w), text, font=font, fill=FOREGROUND)
bg.show()
bg.save('media/converty/test.png')
9 个回答
19
这是一个完整的示例,使用了unutbu的技巧(在Python 3.6和Pillow 5.3.0上测试过):
from PIL import Image, ImageDraw, ImageFont
import textwrap
def draw_multiple_line_text(image, text, font, text_color, text_start_height):
'''
From unutbu on [python PIL draw multiline text on image](https://stackoverflow.com/a/7698300/395857)
'''
draw = ImageDraw.Draw(image)
image_width, image_height = image.size
y_text = text_start_height
lines = textwrap.wrap(text, width=40)
for line in lines:
line_width, line_height = font.getsize(line)
draw.text(((image_width - line_width) / 2, y_text),
line, font=font, fill=text_color)
y_text += line_height
def main():
'''
Testing draw_multiple_line_text
'''
#image_width
image = Image.new('RGB', (800, 600), color = (0, 0, 0))
fontsize = 40 # starting font size
font = ImageFont.truetype("arial.ttf", fontsize)
text1 = "I try to add text at the bottom of image and actually I've done it, but in case of my text is longer then image width it is cut from both sides, to simplify I would like text to be in multiple lines if it is longer than image width."
text2 = "You could use textwrap.wrap to break text into a list of strings, each at most width characters long"
text_color = (200, 200, 200)
text_start_height = 0
draw_multiple_line_text(image, text1, font, text_color, text_start_height)
draw_multiple_line_text(image, text2, font, text_color, 400)
image.save('pil_text.png')
if __name__ == "__main__":
main()
#cProfile.run('main()') # if you want to do some profiling
结果:
26
被接受的答案在处理文本时,没有考虑字体的大小(最多40个字符,不管字体大小和框的宽度是多少),所以结果只是个大概,可能会导致文本超出框的范围或者填不满框。
这里有一个简单的库,可以正确解决这个问题: https://gist.github.com/turicas/1455973
71
你可以使用 textwrap.wrap
这个工具,把 text
分成一个字符串列表,每个字符串的长度最多是 width
个字符:
import textwrap
lines = textwrap.wrap(text, width=40)
y_text = h
for line in lines:
width, height = font.getsize(line)
draw.text(((w - width) / 2, y_text), line, font=font, fill=FOREGROUND)
y_text += height