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