问题
I'm creating a small python program that draws text on a small 128x48 image. It works fine for text that only reaches width of 120, but I can't figure out how to have longer text split into an additional line. How do I go about doing so?
I've attempted using textwrap3, but I couldn't get it to work with Pillow.
The program creates 128x48 images files with a black background and yellow centered text, that is later supposed to be viewed on a device that outputs up to 480i, so simply making the text much smaller to fit additional text width won't be helpful. The font currently used is Arial 18.
Here's the current code used to create the image:
from PIL import Image, ImageDraw, ImageFont
AppName = "TextGoesHere"
Font = ImageFont.truetype('./assets/Arial.ttf', 18)
img = Image.new('RGB', (128, 48), color='black')
d = ImageDraw.Draw(img)
# Get width and height of text
w, h = d.textsize(AppName, font=Font)
# Draw text
d.text(((128-w)/2, (48-h)/2), AppName, font=Font, fill=(255, 255, 0))
img.save('icon.png')
The above code outputs the image like this:

Longer text with width bigger then the image outputs like this (LongerTextGoesHere):

The wanted result should be simular to this:

回答1:
Here's some code that uses binary search with PIL/Pillow to break the text into pieces that fit.
def break_fix(text, width, font, draw):
if not text:
return
lo = 0
hi = len(text)
while lo < hi:
mid = (lo + hi + 1) // 2
t = text[:mid]
w, h = draw.textsize(t, font=font)
if w <= width:
lo = mid
else:
hi = mid - 1
t = text[:lo]
w, h = draw.textsize(t, font=font)
yield t, w, h
yield from break_fix(text[lo:], width, font, draw)
def fit_text(img, text, color, font):
width = img.size[0] - 2
draw = ImageDraw.Draw(img)
pieces = list(break_fix(text, width, font, draw))
height = sum(p[2] for p in pieces)
if height > img.size[1]:
raise ValueError("text doesn't fit")
y = (img.size[1] - height) // 2
for t, w, h in pieces:
x = (img.size[0] - w) // 2
draw.text((x, y), t, font=font, fill=color)
y += h
img = Image.new('RGB', (128, 48), color='black')
fit_text(img, 'LongerTextGoesHere', (255,255,0), Font)
img.show()
回答2:
You can do that pretty simply without needing to code any Python if you use ImageMagick which is installed on most Linux distros and is available for macOS and Windows. So, just in Terminal:
convert -size 128x48 -background black -font Arial -fill yellow -gravity center caption:"Some Text" result.png
Or, with a longer text string:
convert -size 128x48 -background black -font Arial -fill yellow -gravity center caption:"Some Really Really Long Text" result.png
If you really, really want to write Python, Wand is a Python binding for ImageMagick and the function names will mirror those used above.
来源:https://stackoverflow.com/questions/58041361/break-long-drawn-text-to-multiple-lines-with-pillow