HTML页面导出为PDF(JSPDF、ITEXT、WKHTMLTOPDF)

article/2025/9/11 17:26:40

html页面导出pdf,本来是一件很简单的事情,在浏览器直接打印(Mac快捷键为⌘+p;Windows快捷键为ctrl+p),就可以把页面另存为pdf文件,但对于要经常把页面导出为pdf的用户来说并不友好,一个合格程序员的标准就是:做出来的软件猪都要会用,否则你就是猪。

调研了几种html导出pdf的实现方式,这里把要点记录下来分享下。

调研对象优点缺点分页图片表格链接中文特殊字符、样式导出样例备注
jsPDF1、整个过程在客户端执行(不需要服务器参与),调用简单1、生成的pdf为图片形式,且内容失真支持支持支持不支持支持支持
iText1、功能基本可以实现,比较灵活2、生成pdf质量较高1、对html标签严;格,少一个结束标签就会报错;2、后端实现复杂,服务器需要安装字体;3、图片渲染比较复杂(暂时还没解决)支持支持支持支持支持支持
wkhtmltopdf1、调用方式简单(只需执行一行脚本);2、生成pdf质量较高1、服务器需要安装wkhtmltopdf环境;2、根据网址生成pdf,对于有权限控制的页面需要在拦截器进行处理支持支持支持支持支持支持

上面三种是着重调研的三种方式,下面进行简单介绍。


一、html2canvas+jsPDF


这种方式的原理是利用html2canvas遍历页面中的dom节点,渲染成canvas image,再用jsPDF把canvas image转化为pdf,最后转化的pdf的内容都是图片形式,类似于把整个网页截图、切割,再一页一页拼接成一个完整的pdf。

代码样例
html:

<span style="background-color:#f6f8fa"><span style="color:#000000"><code class="language-html"><span style="color:#006666"><<span style="color:#4f4f4f">button</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"exportToPdf"</span>></span>导出为PDF<span style="color:#006666"></<span style="color:#4f4f4f">button</span>></span>
<span style="color:#006666"><<span style="color:#4f4f4f">div</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"export_content"</span>></span>这里是要导出为pdf中的内容
<span style="color:#006666"></<span style="color:#4f4f4f">div</span>></span></code></span></span>

javascript(需要依赖jspdf和html2canvas相关js):

<span style="background-color:#f6f8fa"><span style="color:#000000"><code class="language-javascript"><script src=<span style="color:#009900">"js/jspdf.debug.js"</span>><span style="color:#006666"></<span style="color:#4f4f4f">script</span>></span>
<span style="color:#006666"><<span style="color:#4f4f4f">script</span> <span style="color:#4f4f4f">src</span>=<span style="color:#009900">"js/html2canvas.js"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">script</span>></span>
<span style="color:#006666"><<span style="color:#4f4f4f">script</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"text/javascript"</span>></span><span style="color:#000088">var</span> downPdf = document.getElementById(<span style="color:#009900">"exportToPdf"</span>);downPdf.onclick = <span style="color:#000088">function</span> <span style="color:#4f4f4f">()</span> {html2canvas(document.getElementById(<span style="color:#009900">"export_content"</span>),{dpi: <span style="color:#006666">172</span>,<span style="color:#880000">//导出pdf清晰度</span>onrendered: <span style="color:#000088">function</span> <span style="color:#4f4f4f">(canvas)</span> {<span style="color:#000088">var</span> contentWidth = canvas.width;<span style="color:#000088">var</span> contentHeight = canvas.height;<span style="color:#880000">//一页pdf显示html页面生成的canvas高度;</span><span style="color:#000088">var</span> pageHeight = contentWidth / <span style="color:#006666">592.28</span> * <span style="color:#006666">841.89</span>;<span style="color:#880000">//未生成pdf的html页面高度</span><span style="color:#000088">var</span> leftHeight = contentHeight;<span style="color:#880000">//pdf页面偏移</span><span style="color:#000088">var</span> position = <span style="color:#006666">0</span>;<span style="color:#880000">//html页面生成的canvas在pdf中图片的宽高(a4纸的尺寸[595.28,841.89])</span><span style="color:#000088">var</span> imgWidth = <span style="color:#006666">595.28</span>;<span style="color:#000088">var</span> imgHeight = <span style="color:#006666">592.28</span> / contentWidth * contentHeight;<span style="color:#000088">var</span> pageData = canvas.toDataURL(<span style="color:#009900">'image/jpeg'</span>, <span style="color:#006666">1.0</span>);<span style="color:#000088">var</span> pdf = <span style="color:#000088">new</span> jsPDF(<span style="color:#009900">''</span>, <span style="color:#009900">'pt'</span>, <span style="color:#009900">'a4'</span>);<span style="color:#880000">//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)</span><span style="color:#880000">//当内容未超过pdf一页显示的范围,无需分页</span><span style="color:#000088">if</span> (leftHeight < pageHeight) {pdf.addImage(pageData, <span style="color:#009900">'JPEG'</span>, <span style="color:#006666">0</span>, <span style="color:#006666">0</span>, imgWidth, imgHeight);} <span style="color:#000088">else</span> {<span style="color:#000088">while</span> (leftHeight > <span style="color:#006666">0</span>) {pdf.addImage(pageData, <span style="color:#009900">'JPEG'</span>, <span style="color:#006666">0</span>, position, imgWidth, imgHeight)leftHeight -= pageHeight;position -= <span style="color:#006666">841.89</span>;<span style="color:#880000">//避免添加空白页</span><span style="color:#000088">if</span> (leftHeight > <span style="color:#006666">0</span>) {pdf.addPage();}}}pdf.save(<span style="color:#009900">'content.pdf'</span>);},<span style="color:#880000">//背景设为白色(默认为黑色)</span>background: <span style="color:#009900">"#fff"</span>  })}
<span style="color:#006666"></<span style="color:#4f4f4f">script</span>></span>
</code></span></span>

这种方法的优点是所有的过程都由js在客户端完成,不需要依赖服务器。
目前发现的两个比较明显的缺点:
1、生成的pdf质量不高,失真比较严重(不过在github上这个方法可以适当提高下生成pdf的清晰度Add dpi/scale options for custom resolution by eKoopmans · Pull Request #1087 · niklasvh/html2canvas · GitHub);
2、在分页处如果有图片的话,不会自动识别隔页处理(甚至一行文字也能给你上下一分为二),而是无情地把图片一分为二,满满的违和感~如下图:

github上有一篇文章说明比较详细,还有具体的demo:https://github.com/linwalker/render-html-to-pdf


二、iText


iText是一个第三方报表java插件,可以在后端利用java随意生成、转化pdf文件,提供了很多api,比较灵活。

代码样例
pom依赖:

<span style="background-color:#f6f8fa"><span style="color:#000000"><code class="language-xml"><span style="color:#006666"><<span style="color:#4f4f4f">dependency</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">groupId</span>></span>org.eclipse.birt.runtime.3_7_1<span style="color:#006666"></<span style="color:#4f4f4f">groupId</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">artifactId</span>></span>com.lowagie.text<span style="color:#006666"></<span style="color:#4f4f4f">artifactId</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">version</span>></span>2.1.7<span style="color:#006666"></<span style="color:#4f4f4f">version</span>></span>
<span style="color:#006666"></<span style="color:#4f4f4f">dependency</span>></span>
<span style="color:#006666"><<span style="color:#4f4f4f">dependency</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">groupId</span>></span>org.xhtmlrenderer<span style="color:#006666"></<span style="color:#4f4f4f">groupId</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">artifactId</span>></span>flying-saucer-pdf<span style="color:#006666"></<span style="color:#4f4f4f">artifactId</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">version</span>></span>9.0.8<span style="color:#006666"></<span style="color:#4f4f4f">version</span>></span>
<span style="color:#006666"></<span style="color:#4f4f4f">dependency</span>></span>
<span style="color:#006666"><<span style="color:#4f4f4f">dependency</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">groupId</span>></span>com.itextpdf<span style="color:#006666"></<span style="color:#4f4f4f">groupId</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">artifactId</span>></span>itextpdf<span style="color:#006666"></<span style="color:#4f4f4f">artifactId</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">version</span>></span>5.4.2<span style="color:#006666"></<span style="color:#4f4f4f">version</span>></span>
<span style="color:#006666"></<span style="color:#4f4f4f">dependency</span>></span></code></span></span>

java实现:

<span style="background-color:#f6f8fa"><span style="color:#000000"><code class="language-java">ITextRenderer renderer = <span style="color:#000088">new</span> ITextRenderer();
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont(<span style="color:#009900">"/Users/hehe/share/Fonts/simsun.ttc"</span>, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
OutputStream os = <span style="color:#000088">new</span> FileOutputStream(<span style="color:#009900">"/Users/hehe/Desktop/iTextPDF.pdf"</span>);
String htmlstr = HttpHandler.sendGet(<span style="color:#009900">"http://localhost:10086/test/iTextPDF.html"</span>);<span style="color:#880000">//HttpHandler.sendGet只是单纯获得指定网页的html字符串内容</span>
renderer.setDocumentFromString(htmlstr);
renderer.layout();
renderer.createPDF(os);</code></span></span>

以上只是简单利用html字符串来生成pdf,需要注意的是:
1、如果页面中有中文,服务器端需要下载字体库simsun.ttc,在后台进行引用,同时在页面的样式中加入对应字体的定义,如:body{font-family: SimSun;},否则中文无法渲染(中文处渲染出来的效果是空白);
2、页面中如果有图片,如果图片引用是绝对路径或者base64则不用考虑,如果是相对路径,需要在后台用renderer.getSharedContext().setBaseURL("图片绝对路径目录");来指定图片路径,否则图片无法渲染。
3、要转化的页面必须是标准的XHTML页面,有一处不符合规范就会报错,小编再试的时候就经常报诸如org.xml.sax.SAXParseException;lineNumber: 24; columnNumber: 6;元素类型 "span" 必须由匹配的结束标记 "</span> 终止"之类的错误,所以如果要用iText来大量爬取网络中的页面的话,还是放弃吧,毕竟网上很多页面都是不标准的~


三、wkhtmltopdf


wkhtmltopdf是一个可以把html转为pdf的插件,有windows、linux等平台的版本,最大的特点就是使用简单,语言无关性。
1、下载:官网下载 wkhtmltopdf
2、执行:该插件是“绿色版”,无需编译安装,下载解压后,在bin目录下有wkhtmltoimage和wkhtmltopdf两个文件,生成pdf可以直接运行wkhtmltopdf(也可以把bin目录配置到环境变量),执行wkhtmltopdf -V查看是否可以执行。
执行的时候可能会报错wkhtmltopdf: error while loading shared libraries: libXrender.so.1 或者 ./wkhtmltopdf: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory 具体解决方法可参考wkhtmltopdf: error while loading shared libraries: libXrender.so.1 - SvennD

如果执行完打印出wkhtmltopdf的版本号,则说明OK了,下面来一个打印html页面的例子试试看,就把本页面转化成pdf吧:

<span style="background-color:#f6f8fa"><span style="color:#000000"><code>wkhtmltopdf --disable-smart-shrinking https://blog<span style="color:#009900">.csdn</span><span style="color:#009900">.net</span>/huyuyang6688/article/details/<span style="color:#006666">79710704</span> myBlog<span style="color:#009900">.pdf</span></code></span></span>

执行完之后,就会在当前目录生成一个pdf(当然生成pdf的目录可以指定),--disable-smart-shrinking 这个参数是关闭缩放,如果不加的话,生成的pdf内容会特别“瘦”,不造为啥这个命令在mac环境下不是很有效,不敢在linux环境生成的PDF是正常的。具体更详细的用法可以参考如下文章:
1、HTML 转 PDF 之 wkhtmltopdf 工具简介
2、HTML 转 PDF 之 wkhtmltopdf 工具精讲
3、wkhtmltopdf参数详解
4、解决wkhtmltopdf支持中文和缩放问题:wkhtmltopdf折腾记

与之类似的还有一个叫Phantomjs的插件,效果差不多,还没深入研究。

 

原文地址:html页面导出为pdf(jsPDF、iText、wkhtmltopdf) - 灰信网(软件开发博客聚合)


http://chatgpt.dhexx.cn/article/Vs5B4EBI.shtml

相关文章

html转pdf(总结五种方法Java)

html转pdf&#xff08;总结五种方法Java&#xff09; Java 实现html转pdf&#xff0c;总结五种方法。 推荐使用wkhtmltopdf,Itext 方法一&#xff1a;使用wkhtmltopdf 1、下载插件wkhtmltopdf https://wkhtmltopdf.org/downloads.html 2、本机测试 本目录下cmd进入 输入命…

Java 动态规划

Java中的动态规划 介绍 动态规划典型的被用于优化递归算法&#xff0c;因为它们倾向于以指数的方式进行扩展。动态规划主要思想是将复杂问题&#xff08;带有许多递归调用&#xff09;分解为更小的子问题&#xff0c;然后将它们保存到内存中&#xff0c;这样我们就不必在每次…

PDF如何转换成jpg图片

PDF文件转换成jpg&#xff0c;有些人一看到问题可能有点懵逼&#xff0c;其实就是PDF转换成图片了&#xff0c;只要转换器中的PDF转图片功能中图片格式支持jpg格式&#xff0c;就可以直接转换成jpg图片了&#xff0c;比如奥凯丰 PDF转换大师&#xff0c;支持PDF转jpg、PDF转png…

数据结构和算法Java实现(韩顺平)

目录 稀疏数组 队列 数组模拟队列思路 数组模拟环形队列 链表 单链表的翻转 单链表的逆序输出&#xff08;栈&#xff09; 双向链表 Jasephu 问题 栈 数组模拟 栈实现计算器 中缀表达式 计算器 逆波兰表达式 &#xff08;后缀表达式&#xff09; 中缀转后缀实现计算…

pdf文件转图片(java实现)

项目中pdf文件太大&#xff0c;在手机端打开缓慢。需要将pdf文件转换成图片。加载比较快&#xff0c;增加用户体验。话不多说&#xff0c;直接上干货。 一、在pom引入依赖的jar <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/fontbox --><dependency&g…

袋鼠云与中航金网达成战略合作并成立信创大数据联合实验室

当前&#xff0c;加快推进“新基建”已成为新形势下国家稳定经济发展的重要方针&#xff0c;而作为“新基建底座”的信创产业&#xff0c;有望成为未来中国十年科技发展的核心领域。纵观信创产业近五年发展&#xff0c;产品和技术已从“基本可用”向“好用易用”大跨步迈进&…

基于java实现PDF转图片图片合成PDF

平常在工作中&#xff0c;经常需要用到pdf转换成图片或者图片转换成pdf的功能。能将pdf转换成图片的工具比较多&#xff0c;比如wps就支持转换为图片&#xff0c;不过高清的转换需要开通会员才行&#xff0c;比较麻烦。免费的转换不光清晰度有问题&#xff0c;还存在水印等&…

《Java语言程序设计(第三版 沈泽刚)》编程练习2

编程练习 2 2.1 编写程序&#xff0c;从键盘上输入一个double类型的华氏温度&#xff0c;然后将其转换为摄氏温度输出。转换公式为&#xff1a; 摄氏度 &#xff08; 5 / 9 &#xff09;&#xff08;华氏度 − 32 &#xff09; 摄氏度&#xff08;5/9&#xff09;&#xff08…

PDF怎么转换成jpg图片保存?简单几步就能解决。

在我们的日常工作和生活中&#xff0c;我们经常会和别人在线传输各种文件。但是在传输Word文档、Excel表格、PPT等格式的文件时&#xff0c;文件内容排版和布局容易出现变化。因此&#xff0c;人们在传输文件时一般都将文件转换为PDF&#xff0c;但PDF文件在手机上观看并不方便…

pdf如何转换成jpg图片?

pdf如何转换成jpg图片&#xff1f;PDF&#xff08;Portable Document Format&#xff09;是一种常见的文件格式&#xff0c;由Adobe Systems创建。与其他文档格式相比&#xff0c;它具有固定页面布局和跨平台兼容性等优点&#xff0c;因此广泛应用于电子书、论文、技术手册、合…

PDF怎么转换成jpg图片

PDF怎么转换成jpg图片&#xff1f;在日常工作中&#xff0c;PDF文件是一种非常常用的格式类型。文件存储安全性高&#xff0c;可以保护用户文件的内容&#xff0c;文件的转换也很方便。支持多种文件类型&#xff0c;可自由切换。有的朋友还是比较习惯查阅图片格式的内容&#x…

动态规划(Java)

文章目录 前言一、背包问题二、字符串转化问题三、纸牌问题四、最少贴纸数总结 前言 动态规划的目的就是避免重复计算&#xff0c;在暴力递归的过程中若在计算过程中产生了重复计算那么就可以进行动态规划的优化。以空间换时间&#xff0c;可以根据暴力递归的过程写出动态规划…

袋鼠云与中航金网达成战略合作,成立信创大数据联合实验室

当前&#xff0c;加快推进“新基建”已成为新形势下国家稳定经济发展的重要方针&#xff0c;而作为“新基建底座”的信创产业&#xff0c;有望成为未来中国十年科技发展的核心领域。纵观信创产业近五年发展&#xff0c;产品和技术已从“基本可用”向“好用易用”大跨步迈进&…

北京市委书记蔡奇调研 PingCAP 立足自主研发和开源战略,助推产业数字化转型

2021 年 3 月&#xff0c;开源正式被列入国家十四五规划发展纲要&#xff0c;可以预期&#xff0c;开源将成为中国未来发展基础软硬件技术的关键路径。**3 月 23 日上午&#xff0c;北京市委书记蔡奇一行参观考察 PingCAP&#xff08;平凯星辰&#xff09;&#xff0c;专题调研…

如何把pdf转成图片?

怎么把pdf转成图片&#xff1f;作为上班族&#xff0c;能熟练的使用各种办公软件是职场必备技能&#xff0c;特别是在处理各种类型的文件时候&#xff0c;如果能熟练的将文件格式进行相互转换&#xff0c;那不仅能提升自己的工作效率&#xff0c;也会方便跟自己对接工作的人。就…

袋鼠云与沃趣科技达成战略合作,共同驱动企业数字化升级

12月3日,袋鼠云与沃趣科技正式达成战略合作,并于袋鼠云总部举行签约仪式。沃趣科技创始人&CEO 陈栋、联合创始人&CTO 李建辉、合伙人&总裁 郭华、技术中心负责人 魏兴华,袋鼠云创始人&董事长 陈吉平、联合创始人&CEO 徐进挺、联合创始人&易知微CEO 宁海…

袋鼠云陈吉平:深耕国产自研数字化技术与服务,持续为客户创造价值

在经济面临下行压力、疫情反复等不确定因素之下&#xff0c;推动数字化转型就成为了许多企业的“救命稻草”。然而&#xff0c;较高的数字化转型门槛、不成系统的数据服务&#xff0c;以及缺乏规范的行业标准等都成了企业数字化转型路上的“绊脚石”。 ​ 2015年&#xff0c;…

陈吉平-阿里巴巴离职DBA在35岁总结的职业生涯

导读&#xff1a;去年很多朋友私下或新浪微博上在总结自己的职业生涯与职业规划&#xff0c;也感觉到很纠结与彷徨&#xff0c;尤其技术人的职业生涯&#xff0c;随年龄增加&#xff0c;一些优势逐渐丧失。4月 13 日数据库技术大会的主办方举行的晚宴上&#xff0c;也让本人支持…

从产品到平台和生态,数据中台「竞争」升级

据可靠信源&#xff0c;中国首家数据中台公司袋鼠云已于去年年底完成C轮融资&#xff0c;由中信证券领投&#xff0c;东方富海、杭州凯泰资本跟投。 这意味着自去年以来颇受争议的数据中台赛道已经有公司率先突破C轮魔咒、迈上新台阶。 创投圈存在一个“C轮死”的魔咒&#xff…

B12专访 | 袋鼠云拖雷:未来十年是数据中台的黄金年代

B座12楼(以下简称“B12”&#xff09;&#xff0c;关注创业和投资的互联网媒体&#xff0c;精准覆盖创投圈数十万粉丝&#xff0c;让创新得到赞赏。 最近&#xff0c;B12找到拖雷&#xff0c;聊了聊大众对数据中台的认知误区、袋鼠云的数据中台“51”方法论以及袋鼠云的生态等&…