python - 如何告诉 Pillow 网格是什么以及如何在其中放置文本以使其不会超过网格块?
问题描述
我正在尝试用 Pillow 模块找出一些东西。对于宾果游戏式的东西,我想布置一个 5x5 的网格,并用我在列表中随机生成的问题填充它。到现在为止还挺好。
我已经想出了如何在 Pillow 中放置东西,所以它会在块的中间有文本,但这是手动完成的。我需要弄清楚我是否可以定义特定的块,这样我才能确保文本不会跨入其他块。
这就是我生成所附屏幕截图显示的图像的方式。
这是我到目前为止的代码(我知道字段的输入在它们周围有引号,这是为了在调试过程中更容易。)
def babbelbingo_file():
file = gclient.open_by_key("obfuscated")
babbelbingo = file.get_worksheet(1)
values = babbelbingo.get_all_values()
list_values = [item for sublist in values for item in sublist]
questions = random.sample(list_values, k=24)
return questions
def make_bingocard(name, questions):
image = Image.open('jeevesbot/files/bingokaart.png')
font_name = ImageFont.truetype('jeevesbot/files/Overpass-regular.ttf', 20)
draw = ImageDraw.Draw(image)
wrapper = textwrap.TextWrapper(width=25)
word_list = wrapper.wrap(text=questions[0])
text_new = ''
for ii in word_list[:-1]:
text_new = text_new + ii + '\n'
text_new += word_list[-1]
draw.text((140, 275), 'questions[0]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((274, 275), 'questions[1]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((408, 275), 'questions[2]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((542, 275), 'questions[3]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((676, 275), 'questions[4]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((140, 394), 'questions[5]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((274, 394), 'questions[6]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((408, 394), 'questions[7]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((542, 394), 'questions[8]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((676, 394), 'questions[9]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((140, 513), 'questions[10]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((274, 513), 'questions[11]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((542, 513), 'questions[12]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((676, 513), 'questions[13]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((140, 632), 'questions[14]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((274, 632), 'questions[15]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((408, 632), 'questions[16]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((542, 632), 'questions[17]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((676, 632), 'questions[18]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((140, 751), 'questions[19]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((274, 751), 'questions[20]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((408, 751), 'questions[21]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((542, 751), 'questions[22]', (0, 0, 0), font=font_name, align='left', anchor='mm')
draw.text((676, 751), 'questions[23]', (0, 0, 0), font=font_name, align='left', anchor='mm')
image.save('jeevesbot/files/generated_bingocards/' + name + '.png')
def bingo(name):
questions = babbelbingo_file()
make_bingocard(name, questions)
解决方案
我创建了一个脚本,它结合了我之前评论中链接的答案以及您的代码来实现您正在寻找的内容(我认为)。我的解决方案与您的代码相比,关键是我正在为每个问题而不是一次进行文本换行。
import math
import textwrap
from PIL import Image, ImageDraw, ImageFont
def get_questions():
return [
'this is my first question',
'a second question that wraps into three lines',
'third question',
'this is a very very long question that will wrap a couple of lines because it just wont end'
]
def draw_question(image, question, x_offset, y_offset):
'''
Based on Franck's answer in python PIL draw multiline text on
image, https://stackoverflow.com/a/56205095/189362 .
In this first approach we calculate the amount of lines that we're
going to need, calculate the offset from the top, and then draw
the text line by line, increasing the offset as we go.
'''
draw = ImageDraw.Draw(image)
question_width = 300
question_height = 300
lines = textwrap.wrap(question, width=20)
font = ImageFont.truetype("arial.ttf", 24)
text_color = (255, 0, 0)
line_height = font.getsize(lines[0])[1]
y_text = y_offset + (question_height / 2) - (len(lines) * (line_height / 2))
for line in lines:
line_width = font.getsize(line)[0]
draw.text(
(
x_offset + (question_width - line_width) / 2,
y_text
),
line,
font=font,
fill=text_color
)
y_text += line_height
def draw_question_alt_approach(image, question, x_offset, y_offset):
'''
Another approach would be to first draw the text in a separate
image, calculate its bounding box, and then merge it with our main
image. Result is the same, just a different approach (with better
readable code imho).
'''
draw = ImageDraw.Draw(image)
question_width = 300
question_height = 300
lines = textwrap.wrap(question, width=20)
font = ImageFont.truetype("arial.ttf", 24)
text_color = (255, 0, 0)
text_img = Image.new('RGBA', (question_width, question_height), (255, 255, 255, 0))
text_draw = ImageDraw.Draw(text_img)
text_draw.multiline_text((0, 0), "\n".join(lines), font=font, fill=text_color, align='center')
bbox = text_img.getbbox()
x = int(x_offset + (question_width / 2) - math.floor(bbox[2] / 2))
y = int(y_offset + (question_height / 2) - math.floor(bbox[3] / 2))
image.alpha_composite(text_img, (x,y))
def draw_card(name, questions):
image = Image.open('bingokaart.png')
draw = ImageDraw.Draw(image)
question_positions = [
[ 0, 0 ],
[ 300, 0 ],
[ 0, 300 ],
[ 300, 300 ],
]
for i, question in enumerate(questions):
draw_question_alt_approach(image, question, question_positions[i][0], question_positions[i][1])
image.save('generated_bingocards/' + name + '.png')
def bingo(name):
questions = get_questions()
draw_card(name, questions)
if __name__ == "__main__":
bingo('foo')
给出:
推荐阅读
- getstream-io - 在 getstream 中聚合更新组中的活动
- php - 使用 php 发送电子邮件后无法重定向到另一个页面
- mysql - 计算具有相同 MySQL 的 3 列值的行的出现次数
- python - Python:计算数字变化的次数
- python - 将正则表达式匹配到整个字符串,而不仅仅是字符串的一部分
- ios - CAShapeLayer 出现在 Views 之前
- javascript - 如何在 ExtJs 中集成 java api
- arrays - 无法使用 Angular 插值显示 JSON 数据
- matlab - 在MATLAB中查找一行中唯一零的列号
- python - 停止 sqlalchemy 管理连接