笔记

预览正常,PDF 为何多一页或缺字?

模板报表在浏览器里看着正常,导出 PDF 却多了一页,有时新页只剩一条窄小内容;另一些报表则缺中文。这些现象看起来都发生在打印时,原因却不同。

这里的报表由引擎读取模板和数据,再生成预览与 PDF。模板除了纸张方向,还保存正文区域、页眉页脚和尺寸。此前出现过横向纸张仍沿用纵向正文高度、内容超过可打印宽度,以及字体尚未准备好等问题。

多出一页,通常先看什么?

先核对内容是否真的落在一页可打印区域内,再看分页规则。只调整显示缩放,可能让预览装得下,却没有改变导出引擎使用的物理尺寸。

以 A4 为例,纸张是 210 mm × 297 mm,横向时交换;正文空间还要扣掉边距与页眉页脚:

snippet
text
printableWidth  = pageWidth - leftMargin - rightMargin
printableHeight = pageHeight - topMargin - bottomMargin
                  - pageHeaderHeight - pageFooterHeight

切到横向后,页面高度变小,正文却仍按纵向预留,就可能生成额外一页。宽度超出时,右边一小条内容也可能被分到新页。因此纸张方向、物理宽高、页面宿主和正文区域要一起核对。

这个项目怎样把尺寸对齐?

模板里的长度可能使用 mm、cm、in、pt、pc。项目先统一换算成毫米,计算后再格式化回目标单位,并控制小数位。例如 1 in 是 25.4 mm,1 pt 是 25.4/72 mm;直接取字符串中的数字相减,会把不同单位混在一起。

当前产品使用 A4,因此先按横纵向统一纸张尺寸,再计算可打印区域,更新页面宿主宽度和正文高度。旧模板有两种保存正文高度的位置,同时存在就同时更新;模板分节中的页面也一起处理,避免只改顶层。

非法或缺失长度需要明确处理,不能写回 NaN。这个做法也有适用前提:将来支持标签纸或自定义纸张时,不能继续强制改成 A4;正文高度调整为一页,也没有替长表、动态增长和重复页眉解决全部分页问题。

浏览器有中文,为什么导出仍然缺字?

浏览器可能从系统字体中找到汉字,导出引擎使用的却是自己的字体资源。页面显示正常,只能说明预览路径找到了字形。

可选办法是给导出引擎准备所需字体,并让预览、导出和打印等待同一份加载结果。项目注册 Noto Sans CJK 作为默认字体,相关入口先等注册完成,避免用户很快点击导出时字体还没准备好。

多个调用共享同一个 Promise,减少重复注册。但首次失败后缓存的仍是失败结果,重试还需另行设计。部署时也要检查字体是否进入产物、请求是否成功、字库是否含所需汉字,最终仍以 PDF 字形是否完整为准。

几何用例可以固定横纵向、单位、边距、正文位置和分节,字体替身只能检查加载顺序。验收还要打开 PDF 看页数、边缘残片、中文、换行和打印比例,需要搜索复制时直接操作实际文件。本篇依据已有实现与打印复盘整理,没有重新导出业务报表。

直接截图放进 PDF,会不会简单一些?

如果只需要外观快照,可以把画布转成图片再铺到纸张上。另一个画布原型使用的就是这条路,中文已经画在图片中,外观比较容易保持一致。

代价是文字不能像原生文本一样选择和搜索,清晰度受输出像素与压缩影响。当前原型还是一张画布一页,没有动态分页。模板引擎则重新处理模板、数据和字体,更适合按报表需求检查分页,但也不能未经验证就假定所有内容都是矢量或可复制文本。

返回上一页