求助:PrettyTable生成的表格在Jinja2中排版错乱如何解决
问题解决:PrettyTable在Jinja2+PIL中布局错乱的修复方法
核心原因是字体类型不匹配:
终端默认使用等宽字体(每个字符宽度一致),PrettyTable的列宽计算完全基于字符数量,所以终端显示正常;但PIL生成图片时如果默认用了比例字体(比如宋体、微软雅黑),不同字符(中文、英文、符号)的实际宽度差异很大,导致原本按字符数对齐的表格彻底错乱。
最优解决方案:给PIL指定等宽字体
这是最省心的修复方式,直接让图片渲染环境和终端保持一致的等宽逻辑:
from PIL import Image, ImageDraw, ImageFont # 加载系统中的等宽字体,路径根据系统调整 # Windows示例:"C:/Windows/Fonts/consola.ttf" # macOS示例:"/Library/Fonts/Courier New.ttf" # Linux示例:"/usr/share/fonts/truetype/freefont/FreeMono.ttf" mono_font = ImageFont.truetype("Consolas.ttf", 12) # 渲染表格文本时指定该字体 img = Image.new("RGB", (800, 600), "white") drawer = ImageDraw.Draw(img) # pretty_table_str是你用PrettyTable生成的字符串 drawer.text((20, 20), pretty_table_str, font=mono_font, fill="#000000") img.save("table_output.png")
备选方案:手动适配非等宽字体(不推荐)
如果必须使用比例字体,才需要基于实际像素宽度调整布局,单纯用len()计算字符数不够——因为中文、英文的像素宽度差很多。可以通过PIL的font.getsize()获取每个文本的实际宽度,再重新计算列宽并生成适配的表格:
# 假设已加载比例字体font,以及从JSON读取的table_data field_names = table_data["headers"] rows = table_data["rows"] # 计算每列的最大像素宽度 col_max_widths = [] for col_idx in range(len(field_names)): # 包含表头和所有行的内容 all_content = [field_names[col_idx]] + [row[col_idx] for row in rows] col_max_width = max(font.getsize(content)[0] for content in all_content) col_max_widths.append(col_max_width + 10) # 加额外间距 # 手动拼接表格字符串(替代PrettyTable) table_str = "" # 生成表头 header_parts = [f"{name:<{int(col_max_widths[i]/font.getsize(' ')[0])}}" for i, name in enumerate(field_names)] table_str += "| " + " | ".join(header_parts) + " |\n" table_str += "-" * sum(col_max_widths) + "---\n" # 生成行数据 for row in rows: row_parts = [f"{content:<{int(col_max_widths[i]/font.getsize(' ')[0])}}" for i, content in enumerate(row)] table_str += "| " + " | ".join(row_parts) + " |\n" # 最后用PIL渲染这个手动生成的table_str
你之前调整PrettyTable的列宽参数无效,就是因为该参数是基于等宽字体的字符数设计的,和比例字体的像素宽度逻辑不兼容。优先选等宽字体方案,成本最低效果最好。
内容的提问来源于stack exchange,提问作者Kenny
相关产品推荐
相关产品推荐

