如何使用Python的Pillow实现长文本按单词自动换行(避免侧边截断)
实现Pillow文本的单词自动换行(Word Wrap)
我之前也踩过Pillow文本截断的坑!默认的draw.text()只会在指定宽度处直接截断字符,完全不管单词完整性。要实现按单词换行的效果,我们可以自己封装一个文本处理函数,先把文本拆分成符合宽度要求的多行,再逐行绘制。
核心思路
- 将原始文本按空格拆分为单词列表
- 逐个累加单词,用
draw.textlength()计算当前行的宽度 - 当加入下一个单词会超过指定宽度时,就把当前行作为一行,开始新的一行
- 额外处理单个单词超长的边界情况(避免一行完全放不下一个单词的尴尬)
完整代码示例
from PIL import Image, ImageDraw, ImageFont def wrap_text(draw, text, font, max_width): # 拆分文本为单词列表 words = text.split() if not words: return [] wrapped_lines = [] current_line = words[0] current_width = draw.textlength(current_line, font=font) for word in words[1:]: word_width = draw.textlength(word, font=font) # 计算加上当前单词和空格后的总宽度 combined_width = current_width + draw.textlength(' ', font=font) + word_width if combined_width <= max_width: # 可以加入当前行,更新行内容和宽度 current_line += ' ' + word current_width = combined_width else: # 超过宽度,先把当前行存入结果,开始新行 wrapped_lines.append(current_line) current_line = word current_width = word_width # 处理单个单词超长的情况:强制拆分字符 if current_width > max_width: temp_line = '' temp_width = 0 for char in current_line: char_width = draw.textlength(char, font=font) if temp_width + char_width <= max_width: temp_line += char temp_width += char_width else: wrapped_lines.append(temp_line) temp_line = char temp_width = char_width wrapped_lines.append(temp_line) current_line = '' current_width = 0 # 把最后一行加入结果 if current_line: wrapped_lines.append(current_line) return wrapped_lines # 测试示例 if __name__ == '__main__': # 创建空白图片 img = Image.new('RGB', (400, 300), color='white') draw = ImageDraw.Draw(img) # 设置字体(可替换成你本地的字体路径,或用默认字体) try: font = ImageFont.truetype('arial.ttf', 20) except: font = ImageFont.load_default(size=20) # 需要绘制的长文本 long_text = "When using the Pillow library in Python to write text, the default generated text will be truncated on the side. I need to achieve the effect of automatic truncation from the end of the word, that is, to implement the word wrap function." # 调用换行函数,指定最大宽度为380(留10px左右边距) wrapped_lines = wrap_text(draw, long_text, font, 380) # 逐行绘制文本,自定义行间距 y_position = 20 line_spacing = 25 for line in wrapped_lines: draw.text((10, y_position), line, font=font, fill='black') y_position += line_spacing # 保存结果图片 img.save('word_wrap_text.png')
关键细节说明
draw.textlength()是Pillow 9.1.0+新增的方法,用来计算文本宽度,比旧版的textsize()更准确(textsize()已被官方废弃)- 函数里额外处理了单个单词超长的场景,避免出现一行完全放不下一个单词的问题
- 你可以根据需求调整
line_spacing(行间距)和边距数值,让文本显示更美观
这样处理后,文本就会自动在单词末尾换行,再也不会出现截断半个单词的情况啦!
内容的提问来源于stack exchange,提问作者MRA1412




