根本原因是wkhtmltopdf默认不支持中文和JavaScript,需配置中文字体路径并启用JS延迟渲染;ECharts需静态数据+全局变量绑定;weasyprint虽简化字体配置但不支持JS图表。
用 pdfkit 生成带样式的 PDF,但中文显示是方块?
根本原因是默认字体不支持中文。pdfkit 底层调用 wkhtmltopdf,它不自带中文字体,html 里写了 font-family: "microsoft yahei" 也没用——系统没告诉它去哪儿找这个字体文件。
实操建议:
- 下载一个免版权的中文字体(如
NotoSansCJKsc-Regular.otf),放到项目目录下,比如./fonts/ - 在 HTML 中用
@font-face显式声明,并确保src: url(...)是绝对路径或wkhtmltopdf能访问到的路径(本地开发时推荐用file:///绝对路径) - 启动
wkhtmltopdf时加参数:--enable-local-file-access,否则字体文件读不到 - Python 中调用示例:
import pdfkit<br>options = {<br> 'enable-local-file-access': '',<br> 'quiet': ''<br>}<br>pdfkit.from_file('report.html', 'out.pdf', options=options)
导出含 ECharts 图表的 PDF,为什么图是空的?
ECharts 是前端 JS 渲染的,而 wkhtmltopdf 默认不执行 JavaScript,或者执行时机不对(DOM 渲染完、图表还没初始化完就截图了)。
实操建议:
- 必须启用 JS 支持:加选项
--javascript-delay 2000(单位毫秒),给图表留够渲染时间 - 确保 ECharts 实例绑定在全局变量上(如
window.myChart = echarts.init(...)),方便后续调试 - 避免使用异步数据接口:PDF 生成环境没有网络或 CORS 限制,直接用静态 JSON 数据初始化图表更稳
- 如果仍空白,加一段调试 JS 到 HTML 底部:
<script>console.log('chart rendered:', window.myChart?.getOption?.());</script>,再用wkhtmltopdf --debug-javascript查日志
用 weasyprint 替代 pdfkit,能绕过中文字体和 JS 问题吗?
能部分绕开,但代价明确:weasyprint 不执行 JS,也不支持 Canvas/SVG 动态渲染——ECharts、Chart.js 这类基于 Canvas 的图表会直接消失;但它对 CSS 支持更好,中文字体配置更直观。
实操建议:
- 中文字体只需在 CSS 里写清楚路径:
@font-face {<br> font-family: "Noto Sans CJK SC";<br> src: url("./fonts/NotoSansCJKsc-Regular.otf");<br>},然后全局设body { font-family: "Noto Sans CJK SC" } - 图表得换方案:用服务端生成 PNG(如
matplotlib或plotly.io.write_image),再以<img>嵌入 HTML - 注意分页:表格跨页断裂很常见,加 CSS:
table { break-inside: avoid; }<br>tr { break-inside: avoid; } - 性能比
pdfkit慢不少,大数据量报表生成时间可能翻倍
导出 PDF 后数字对不齐、小数点错位,是不是字体问题?
大概率不是字体,而是用了等宽字体以外的字体 + 表格用了 text-align: right。非等宽字体下,"100.00" 和 "9.99" 实际像素宽度差很多,右对齐就会看起来“飘”。
实操建议:
- 数值列强制用等宽字体:
.number-col { font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; } - 别依赖 HTML 表格自动撑宽,给每列设固定
width或用table-layout: fixed - 小数统一补零(后端格式化好),避免
9.9和9.90混用 - 如果用的是金额,加千分位分隔符前确认 PDF 渲染引擎是否支持 Unicode 符号(
窄空格比普通空格更稳)











