使用Pillow实现多行文本居中且不超出1080x1080图像
问题
我正在开发一个Sigma Male表情包生成器,需求是将预设的Sigma Male段子/语录叠加到1080x1080固定尺寸的Sigma Male图像上,格式要求:
- 居中显示一行
Sigma-Male Rule #X标题 - 标题下方展示搞笑生活建议(比如
Don't be part of the problem, be the whole problem)
目前遇到的问题:添加生活建议文本时容易超出图像范围,手动换行能解决但无法自动化。希望实现自动换行+多行文本居中,同时单行段子也能相对于标题保持合适的居中位置。
原代码:
import numpy as np import cv2 from PIL import Image, ImageDraw, ImageFont import textwrap my_image = Image.open("Bateman1Raw resized.jpg") title_font = ImageFont.truetype('Bebas-Regular.ttf', 100) title_text = "Sigma Male Rule #1" text_test='Don\'t be part of the\n problem, be the whole problem' image_editable = ImageDraw.Draw(my_image) image_editable.text((200,400), title_text, (255, 255, 255), font=title_font,stroke_width=2,stroke_fill='black') image_editable.text((0,500), words,(255, 255, 255),align='center',font=title_font,stroke_width=2,stroke_fill='black') my_image.save("result.jpg")
解决方案
核心思路是利用textwrap自动计算换行,结合PIL的文本尺寸计算功能,实现标题和正文的自动居中排版:
from PIL import Image, ImageDraw, ImageFont import textwrap # 加载固定尺寸图像 img = Image.open("Bateman1Raw resized.jpg") img_width, img_height = img.size # 1080x1080 # 设置字体(正文字号可按需调整,避免溢出) title_font = ImageFont.truetype('Bebas-Regular.ttf', 100) body_font = ImageFont.truetype('Bebas-Regular.ttf', 70) # 文本内容 title_text = "Sigma Male Rule #1" body_text = "Don't be part of the problem, be the whole problem" draw = ImageDraw.Draw(img) # --- 处理标题:水平居中 --- title_bbox = draw.textbbox((0,0), title_text, font=title_font) title_width = title_bbox[2] - title_bbox[0] title_x = (img_width - title_width) // 2 title_y = 300 # 可根据视觉需求调整标题垂直位置 draw.text((title_x, title_y), title_text, (255,255,255), font=title_font, stroke_width=2, stroke_fill='black') # --- 处理正文:自动换行+居中 --- # 计算每行最大字符数(留20%左右的边距,避免贴边) max_line_length = int(img_width * 0.8 / body_font.getsize('A')[0]) wrapped_text = textwrap.fill(body_text, width=max_line_length) # 计算换行后正文的整体尺寸 body_bbox = draw.textbbox((0,0), wrapped_text, font=body_font) body_width = body_bbox[2] - body_bbox[0] # 正文位置:水平居中,垂直在标题下方预留间距 body_x = (img_width - body_width) // 2 body_y = title_y + (title_bbox[3] - title_bbox[1]) + 50 # 标题与正文间留50px间距 draw.text((body_x, body_y), wrapped_text, (255,255,255), font=body_font, stroke_width=2, stroke_fill='black', align='center') img.save("result.jpg")
关键改进点:
- 用
textbbox准确计算文本宽高,替代老旧的getsize方法 - 自动计算标题和正文的水平居中坐标,无需硬写固定值
- 通过
textwrap.fill根据图像宽度自动换行,完全实现自动化 - 正文与标题的间距根据标题高度动态计算,保证排版一致性
- 单独设置正文字号,进一步降低溢出风险(可根据需求调整)
内容的提问来源于stack exchange,提问作者TerryStone
相关产品推荐
相关产品推荐

