python的PIL绘制多行文本的图像。

[英]python PIL draw multiline text on image


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. Here is my code:

我试着在图像底部添加文本,实际上我已经做过了,但是如果我的文本更长,那么图像宽度从两边都剪下来,为了简化,如果文本长度大于图像宽度,我希望文本是多行的。这是我的代码:

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

5 个解决方案

#1


34  

You could use textwrap.wrap to break text into a list of strings, each at most width characters long:

您可以使用textwrap。将文本转换成字符串列表,每个字符串的宽度都是最长的:

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

#2


4  

The accepted answer wraps text without measuring the font (max 40 characters, no matter what the font size and box width is), so the results are only approximate and may easily overfill or underfill the box.

被接受的答案不需要测量字体(最多40个字符,不管字体大小和宽度是多少),所以结果只是近似的,很容易填充或填充。

Here is a simple library which solves the problem correctly: https://gist.github.com/turicas/1455973

这里有一个简单的库,可以正确地解决这个问题:https://gist.github.com/turicas/1455973。

#3


0  

text = textwrap.fill("test ",width=35)
self.draw.text((x, y), text, font=font, fill="Black")

#4


0  

All recommendations about textwrap usage fail to determine correct width for non-monospaced fonts (as Arial, used in topic example code).

关于textwrap用法的所有建议都不能确定非单间距字体的正确宽度(如Arial,在主题示例代码中使用)。

I've wrote simple helper class to wrap text regarding to real font letters sizing:

我编写了一个简单的助手类来包装文本关于真正的字体大小:

class TextWrapper(object):
    """ Helper class to wrap text in lines, based on given text, font
        and max allowed line width.
    """

    def __init__(self, text, font, max_width):
        self.text = text
        self.text_lines = [
            ' '.join([w.strip() for w in l.split(' ') if w])
            for l in text.split('\n')
            if l
        ]
        self.font = font
        self.max_width = max_width

        self.draw = ImageDraw.Draw(
            Image.new(
                mode='RGB',
                size=(100, 100)
            )
        )

        self.space_width = self.draw.textsize(
            text=' ',
            font=self.font
        )[0]

    def get_text_width(self, text):
        return self.draw.textsize(
            text=text,
            font=self.font
        )[0]

    def wrapped_text(self):
        wrapped_lines = []
        buf = []
        buf_width = 0

        for line in self.text_lines:
            for word in line.split(' '):
                word_width = self.get_text_width(word)

                expected_width = word_width if not buf else \
                    buf_width + self.space_width + word_width

                if expected_width <= self.max_width:
                    # word fits in line
                    buf_width = expected_width
                    buf.append(word)
                else:
                    # word doesn't fit in line
                    wrapped_lines.append(' '.join(buf))
                    buf = [word]
                    buf_width = word_width

            if buf:
                wrapped_lines.append(' '.join(buf))
                buf = []
                buf_width = 0

        return '\n'.join(wrapped_lines)

Example usage:

使用示例:

wrapper = TextWrapper(text, image_font_intance, 800)
wrapped_text = wrapper.wrapped_text()

It's probably not super-fast, because it renders whole text word by word, to determine words width. But for most cases it should be OK.

它可能不是超快的,因为它通过逐字呈现整个文本,来确定单词的宽度。但在大多数情况下,它应该是可以的。

#5


-2  

You could use PIL.ImageDraw.Draw.multiline_text().

您可以使用PIL.ImageDraw.Draw.multiline_text()。

draw.multiline_text((WIDTH, HEIGHT), TEXT, fill=FOREGROUND, font=font)

You even set spacing or align using the same param names.

您甚至可以使用相同的param名称设置间距或对齐。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2011/10/08/4f537113eb85edfb620f831b0c69816b.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com