服务端pdf渲染方案

PDF渲染生成,并在前端预览实现方案

近期需要每天查询数据,生成PDF,并在前端实现预览效果,需要满足以下几点要求。

  1. 严格控制字体、字体大小、段落格式等。
  2. 加入图片、报表。
  3. 书签,水印,注释等。
  4. 能根据用户的问题匹配PDF中最接近答案的位置,在前端实现定位效果,可能有多个文档。

首先PDF生成预览有两种实现方案

  1. 后端返回数据,前端首先生成DOM结构,再利用浏览器、JavaScript生成PDF并预览。
  2. 后台获取数据并生成PDF,将文件流返回前端,前端只负责预览。

前三个需求算是比较基本的,前后端都可以实现,但是第四个需求涉及到用户意图理解问题相似度匹配,且项目中部分文件PDF已有(规章制度、合同等),固定且无法更改,无需生成也不应该渲染生成。所以思路应该是在服务端生成PDF。

wkhtml2pdf

wkhtml2pdf是一个利用QT Webkit内核将html渲染成pdf的命令行工具,支持Mac、Linux、Windows系统,下载地址使用文档中对所有命令行参数进行了说明。

使用方法很简单

D:\tools\wkhtmltopdf\bin\wkhtmltoimage.exe https://baidu.com baidu.png
D:\tools\wkhtmltopdf\bin\wkhtmltoimage.exe https://baidu.com baidu.pdf
D:\tools\wkhtmltopdf\bin\wkhtmltopdf.exe .\test.html test.pdf

前两条命令在本人的电脑上运行速度非常慢,不知道什么原因,第三条命令为纯静态页面,没有Javascript,运行也比较慢,生成的代码块、表格等不支持跨页,存在大片空白(不知道是否参数未设置)。结合网上查阅的一些资料,并没有选择该方案,原因如下。

  1. 效率问题,转换速度较慢。
  2. 上一次代码提交已经是几年前,维护不活跃,前端CSS、JavaScript更新频繁,使用的Webkit内核比较旧,许多特性不支持
  3. wkhtmltopdf对动态页面的支持效果一般,动态页面输出pdf的需求中最好不要有太复杂的javascript逻辑,例如Vue、React等前端框架。参考该文章及该文章的评论区。

pandoc

pandoc是一个开源的格式转换命令行工具,涵盖了几乎所有格式或非格式化文件的相互转化,官方文档自称为格式转化的“瑞士军刀”。
在这里插入图片描述
不过格式支持多且全的所带来的缺点就是文件之间的转换可能要通过中间格式,例如markdown转化为pdf中间格式可以是latex、html等,pandoc无法做到各种格式之间的完美转化,它保留了文档的主要元素,但是忽略了一些细节。

默认情况下,pandoc使用Latex生成pdf,需要安装pdf引擎(通过–pdf-engine指定),或者可以通过ConText、html等中间格式转换,其中生成html再转为pdf需要依赖wkhtmltopdf。
不同的中间转化格式有不同的参数指定生成pdf的格式。

通过wkhtmltopdf生成pdf

pandoc -t html -s ./"Spring AOP-springaop.md" -o aop.pdf

从输入输出文件名中识别是markdown转pdf,-s参数意为–standalone,生成html会包含html的完整结构而不是仅有主体内容,-t指定中间格式为html。
生成的pdf调用了wkhtmltopdf,且与直接调用wkhtmltopdf效果不一样,可以看到文档边距比较大,更多参数variables for wkhtmltopdf
在这里插入图片描述

通过xelatex生成pdf

中间格式为latex,需要安装tex工具,这里推荐安装texlive,可以在线或者离线安装,安装完之后即有latex转pdf的引擎。
值得注意的是latex默认不支持中文字体,需要特别指定。使用以下命令查看可用的中文字体

# 指定输出格式,筛选中文字体
fc-list -f "%{family}\n" :lang=zh

以下命令指定中文字体为楷体,从markdown转化为pdf格式

pandoc -s -f markdown -t pdf -V CJKmainfont="KaiTi" -V mainfont="Times New Roman" --pdf-engine=xelatex ".\Hadoop3 HA高可用集群搭建-hadoop3ha高可用集群搭建.md" -o test.pdf

如果你想查看中间生成的tex文件,可以修改-o参数生成tex文件,再使用xelatex tex文件名生成pdf。
在这里插入图片描述
在windows系统上执行上述命令会报编码错误,原因是pandoc的输入输出默认都是utf-8格式,除了保证文件格式为utf-8外,命令行也要是utf-8编码,而windows控制台默认GBK编码,需要执行chcp 65001转换为utf8。

基于wkhtmltopdf的转换就不说了,只要定制好latex模板和参数,理论上基于latex的转换可以控制pdf的每一个细节,latex本身就是优秀的排版工具,但是语法多,使用复杂,学习成本较高,在尝试过程中,仅仅是控制字体大小就花费了大量时间且没有找到解决方案,耗时费力,适合有时间捣鼓的人。

selenium

selenium是一个自动化测试工具,可以自动控制浏览器,常用于自动化测试、爬虫等领域,支持Edge、Chromium、Firefox等内核的浏览器,提供了常见编程语言的接口。

使用程序控制浏览器打开网页,然后执行另存为pdf的功能即可保存html为pdf,和正常运行的浏览器效果无异,渲染各种图片、执行JavaScript脚本,发送网络请求等等。
要操作浏览器,需要下载对应浏览器对应版本的驱动程序。
以下是一个Python中selenium的示例。

import base64

from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.print_page_options import PrintOptions


class PdfPrinter:
    def __init__(self):
        service = Service(executable_path=r'D:\tools\web_driver\chromedriver')
        options = Options()
        # 忽略权限
        options.add_argument('--no-sanbox')
        self.driver = Chrome(service=service, options=options)

    def print(self, url):
        self.driver.get(url)
        options = PrintOptions()
        print(options.page_width)
        # A4纸大小
        options.page_width = 21.6
        options.page_height = 27.9
        # 浏览器打印时的选项,加载背景图形
        # options.background = True
        data = self.driver.print_page(options)
        with open('./data1.pdf', 'wb') as f:
            f.write(base64.b64decode(data))


if __name__ == '__main__':
    PdfPrinter().print('https://www.huya.com/16921847')

PringOptions支持浏览器打印的所有选项且更灵活。

JasperReport + iText

之前用Java做毕业设计的时候同样有后台生成pdf报表的需求,最初的尝试是使用JasperReport设计模板,后台填充数据动态生成PDF,结果发现还是不太灵活,样式控制复杂,不如写html、css来的方便,最终还是采用了后台自动化浏览器实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值