ReportLab显示中文需注册中文字体并设字体族,生成表格应使用Table类预处理数据为字符串,PDF损坏多因未调用canvas.save()或含非法字符,Jinja2仅用于内容渲染不可介入布局层。

ReportLab画PDF时中文显示成方块或乱码怎么办
根本原因是ReportLab默认不支持中文字体,直接用drawString或Paragraph写中文,会触发UnicodeEncodeError或渲染成空白方块。
必须显式注册中文字体(如NotoSansCJK、simhei.ttf等),且字体文件路径要真实存在。Windows下常见误用simhei.ttf但实际系统里是simhei.ttf或msyh.ttc,Linux/macOS则通常没有预装中文字体。
- 用
pdfmetrics.registerFont注册字体前,先用os.path.exists确认字体文件路径可读 - 注册后必须调用
pdfmetrics.registerFontFamily把字体设为“标准字体族”,否则Paragraph仍可能 fallback 到默认无中文的字体 - 推荐用
NotoSansCJK-SimplifiedChinese(Google开源,免版权),下载后解压取NotoSansCJKsc-Regular.otf即可
用ReportLab动态填充数据生成表格报表的正确姿势
别用drawString一行行算坐标拼表格——容易错位、无法自动换页、列宽难控制。ReportLab原生的Table类才是正解,但要注意它对数据类型敏感:所有单元格内容必须是字符串或Flowable对象(如Paragraph),不能直接塞int或datetime。
- 数据预处理阶段统一转
str(),日期用.strftime('%Y-%m-%d')格式化,数值建议用f"{x:.2f}"避免科学计数法 -
Table的style参数必须传TableStyle实例,不能传列表字面量;常用样式如('GRID', (0,0), (-1,-1), 0.5, colors.grey)控制边框 - 列宽用
colWidths指定,单位是磅(point),不是像素;建议用[1*inch, 2*inch, ...]比硬写数字更可靠
ReportLab生成PDF后文件打不开或提示“损坏”
最常见原因是没调用canvas.save(),或者canvas对象被提前del或作用域结束导致缓冲区未刷出。另一个隐蔽问题是PDF内容含非法字符,比如数据库字段里混入了\x00、\uFFFD这类控制符,ReportLab不会报错但输出文件不可读。
立即学习“Python免费学习笔记(深入)”;
- 确保
canvas.save()在with open(...)上下文管理器的finally块或之后执行,不要依赖GC - 对所有外部输入(尤其是数据库字段、用户提交文本)做清洗:
text.replace('\x00', '').replace('\ufffd', '') - 生成后用
pdfplumber.open()或命令行pdfinfo快速验证文件结构是否合法
ReportLab和Jinja2模板混合使用的边界在哪
ReportLab本身不是模板引擎,硬套Jinja2生成Paragraph内容可以,但千万别用Jinja2去拼整个PageTemplate或Frame结构——逻辑会失控,调试极难。适合的分工是:Jinja2负责“内容层”(比如把JSON数据转成[[row1], [row2]]这种表格数据),ReportLab负责“布局层”(定义页眉、分栏、字体、表格样式)。
- Jinja2渲染结果必须是纯Python结构(list/dict/str),不能返回
Markup或HTML字符串——ReportLab不吃那一套 - 如果报表需要条件样式(比如金额"is_negative": True字段),样式逻辑留在ReportLab的
TableStyle里用if判断 - 避免在Jinja2模板里调用
reportlab.platypus.Paragraph——这会让模板强依赖ReportLab,违背关注点分离
ReportLab的坑不在语法,而在字体加载时机、PDF流写入顺序、以及数据到布局的映射精度。一个registerFont漏掉,整份报表就变方块;一个save()忘写,生成的PDF就是0字节。这些地方没法靠“多试几次”绕过去,得盯住每一步的返回值和文件状态。










