pdfjs渲染PDF至canvas后转存为PDF体积大幅增大的原因及优化咨询
问题1:为什么PDF转JPEG再转回PDF体积大幅增长?
核心原因是你做了「矢量转栅格」的无效转换:
- 绝大多数正常的PDF文件存储的是结构化内容:文字、矢量图形、少量内嵌位图,都是用指令式的方式描述,比如“在坐标(100,200)处用12号宋体渲染文字‘测试’”,只需要几十字节就能描述的内容,栅格化后变成像素点要占几KB甚至几十KB。你用
pdfjs把PDF渲染到canvas的时候,相当于把所有矢量结构全部打平成了一整张铺满A4页的位图,哪怕分辨率和原PDF视口一致,整页位图的体积天然就比原矢量PDF大得多。 - 额外的编码冗余:你从
canvas导出JPEG的时候做了一次编码,调用jsPDF的addImage时,即便你传的已经是JPEG数据,jsPDF默认还是会对图片做二次编码,你代码里设的compression: 'MEDIUM'反而会引入额外的编码开销,甚至出现画质劣化、体积反而上涨的情况。 - 你试的灰度渲染没用,本质还是因为你输出的是整页栅格图,哪怕是灰度单通道,整页图的体积还是远大于原矢量PDF的体积。
问题2:客户端侧的优化方案
如果要在不损失分辨率的前提下把体积压到接近原文件大小,优先放弃整页栅格回退的方案:
- 优先用
pdf-lib做PDF修改:如果你要做的修改是文本替换、加标注、替换指定内嵌图片这类结构化操作,直接用pdf-lib操作原PDF的结构,完全不需要栅格化页面,修改后的PDF体积基本和原文件一致,还能保留所有矢量内容的清晰度。
如果必须用canvas做修改(比如加手绘涂鸦、页面特效这类只能在canvas实现的操作),可以做以下优化: - 导出
canvas的时候直接控制JPEG质量,导出参数quality设为0.8~0.9即可,导出后直接将JPEG的base64数据传给jsPDF,关闭jsPDF的二次压缩,避免重复编码的开销。 - 局部修改不要导出整页图:如果你只是修改了页面的某一块区域,只裁剪修改区域的
canvas内容导出成透明PNG,再把这张小图叠到原PDF页上,保留原PDF的所有矢量内容,体积只会增加几KB到几十KB,不会出现数倍增长。 - 生成PDF后可以用
pako对PDF的内部流做二次flate压缩,jsPDF默认生成的PDF压缩率通常偏低,手动压缩后通常能减少20%~30%的体积。
内容的提问来源于stack exchange,提问作者Aleksey S
相关产品推荐
相关产品推荐

