您现在的位置:新闻首页>资本 > 如何将HTML转成PDF?方法介绍
如何将HTML转成PDF?方法介绍
在本文中,我将展示如何使用 Node.js、Puppeteer、headless Chrome 和 Docker 从样式复杂的 React 页面生成 PDF 文档。
相关:《nodejs 教程》
背景:几个月前,一个客户要求我们开发一个功能,用户可以得到 PDF 格式的 React 页面内容。该页面基本上是患者病例的报告和数据可视化结果,其中包含许多 SVG。另外还有一些特殊的请求来操纵布局,并对 HTML 元素进行一些重新排列。因此与原始的 React 页面相比,PDF 中应该有不同的样式和额外的内容。
由于这个任务比用简单的 CSS 规则解决要复杂得多,所以我们先探讨了可能的实现方法。我们找到了 3 个主要解决方案。这篇博文将指导你了解它们的可能性并最终实施。
目录:在客户端还是服务器端生成?方案1:从 DOM 制作屏幕截图方案2:仅使用 PDF 库
最终方案3:Node.js、Puppeteer 和 Headless Chrome
样式控制将文件发送到客户端并保存在 Docker 中使用 Puppeteer方案3 +1:CSS打印规则总结在客户端还是服务器端生成?
在客户端和服务器端都可以生成PDF文件。但是让后端处理它可能更有意义,因为你并不想耗尽用户浏览器可以提供的所有资源。
即便如此,我仍然会展示这两种方法的解决方案。
方案1:从 DOM 制作屏幕截图
乍一看,这个解决方案似乎是最简单的,事实证明的确是这样,但它有其自身的局限性。如果你没有特殊需求,例如在 PDF 中选择文本或对文本进行搜索,那么这就是一种简单易用的方法。
此方法简单明了:从页面创建屏幕截图,并把它放到 PDF 文件中。非常直截了当。我们可以使用两个包来实现:
Html2canvas,根据 DOM 生成截图jsPdf,一个生成PDF的库
开始编码:
npm install html2canvas jspdf
import html2canvas from 'html2canvas' import jsPdf from 'jspdf' function printPDF () { const domElement = document.getElementById('your-id') html2canvas(domElement, { onclone: (document) => { document.getElementById('print-button').style.visibility = 'hidden' }}) .then((canvas) => { const img = canvas.toDataURL('image/png') const pdf = new jsPdf() pdf.addImage(imgData, 'JPEG', 0, 0, width, height) pdf.save('your-filename.pdf') })
就这样!
请注意 html2canvas 的 onclone方法。当你在截图之前需要操纵 DOM(例如隐藏打印按钮)时,它是非常方便的。我看到过很多使用这个包的项目。但不幸的是,这不是我们想要的,因为我们需要在后端完成对 PDF 的创建工作。
方案2:只使用 PDF 库
NPM上有几个库,如 jsPDF(如上所述)或PDFKit。他们的问题是,如果我想使用这些库,我将不得不重新调整页面结构。这肯定会损害可维护性,因为我需要将所有后续更改应用到 PDF 模板和 React 页面中。
请看下面的代码。你需要亲自手动创建 PDF 文档。你需要遍历 DOM 并找出每个元素并将其转换为 PDF 格式,这是一项繁琐的工作。必须找到一个更简单的方法。
doc = new PDFDocument doc.pipe fs.createWriteStream('output.pdf') doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100) doc.image('path/to/image.png', { fit: [250, 300], align: 'center', valign: 'center' }); doc.addPage() .fontSize(25) .text('Here is some vector graphics...', 100, 100) doc.end()
这段代码段来自 PDFKit 文档。但是如果你的目标是直接生成一个 PDF 文件,而不是对一个已经存在的(并且不断变化的)HTML 页面进行转换,它还是很有用的。
最终方案3:基于 Node.js 的 Puppeteer 和 Headless Chrome
什么是Puppeteer?其文档中写道:
Puppeteer 是一个 Node 库,它提供了一个高级 API 来控制 DevTools 协议上的 Chrome 或 Chromium。 Puppeteer 默认以 headless 模式运行 Chrome 或 Chromium,但其也可以被配置为完整的(non-headless)模式运行。
它本质上是一个可以从 Node.js 运行的浏览器。如果你读过它的文档,其中首先提到的就是你可以用 Puppeteer 来生成页面的截图和PDF。优秀!这正是我们想要的。
先用 npmi i puppeteer 安装 Puppeteer,并实现我们的功能。
这是一个简单的功能,可导航到 URL 并生成站点的 PD F文件。
首先,我们启动浏览器(仅在 headless 模式下支持 PDF 生成),然后打开新页面,设置视口,并导航到提供的URL。
设置 waitUntil:'networkidle0' 选项意味着当至少500毫秒没有网络连接时,Puppeteer 会认为导航已完成。 (可以从API docs 获取更多信息。)
之后,我们将 PDF 保存为变量,关闭浏览器并返回 PDF。
注意:page.pdf 方法接收 options 对象,你可以使用 'path' 选项将文件保存到磁盘。如果未提供路径,则 PDF 将不会被保存到磁盘,而是会得到缓冲区。(稍后我将讨论如何处理它。)
如果需要先登录才能从受保护的页面生成 PDF,首先你要导航到登录页面,检查表单元素的 ID 或名称,填写它们,然后提交表单:
await page.type('#email', process.env.PDF_USER) await page.type('#password', process.env.PDF_PASSWORD) await page.click('#submit')
要始终将登录凭据保存在环境变量中,不要硬编码!
样式控制
Puppeteer 也有这种样式操作的解决方案。你可以在生成 PDF 之前插入样式标记,Puppeteer 将生成具有已修改样式的文件。
await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })将文件发送到客户端并保存
好的,现在你已经在后端生成了一个 PDF 文件。接下来做什么?
如上所述,如果你不把文件保存到磁盘,将会得到一个缓冲区。你只需要把含有适当内容类型的缓冲区发送到前端即可。
printPDF.then(pdf => { res.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length }) res.send(pdf)
现在,你只需在浏览器向服务器发送请求即可得到生成的 PDF。
function getPDF() { return axios.get(`${API_URL}/your-pdf-endpoint`, { responseType: 'arraybuffer', headers: { 'Accept': 'application/pdf' } })
一旦发送了请求,缓冲区的内容就应该开始下载了。最后一步是将缓冲区数据转换为 PDF 文件。
savePDF = () => { this.openModal(‘Loading…’) // open modal return getPDF() // API call .then((response) => { const blob = new Blob([response.data], {type: 'application/pdf'}) const link = document.createElement('a') link.href = window.URL.createObjectURL(blob) link.download = `your-file-name.pdf` link.click() this.closeModal() // close modal }) .catch(err => /** error handling **/) } <button onClick={this.savePDF}>Save as PDF</button>
就这样!如果单击“保存”按钮,那么浏览器将会保存 PDF。
在 Docker 中使用 Puppeteer
我认为这是实施中最棘手的部分 —— 所以让我帮你节省几个小时的百度时间。
官方文档指出“在 Docker 中使用 headless Chrome 并使其运行起来可能会非常棘手”。官方文档有疑难解答部分,你可以找到有关用 Docker 安装 puppeteer 的所有必要信息。
如果你在 Alpine 镜像上安装 Puppeteer,请确保在看到页面的这一部分时再向下滚动一点。否则你可能会忽略一个事实:你无法运行最新的 Puppeteer 版本,并且你还需要用一个标记禁用 shm :
否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。
方案 3 + 1:CSS 打印规则
可能有人认为从开发人员的角度来看,简单地使用 CSS 打印规则很容易。没有 NPM 模块,只有纯 CSS。但是在跨浏览器兼容性方面,它的表现如何呢?
在选择 CSS 打印规则时,你必须在每个浏览器中测试结果,以确保它提供的布局是相同的,并且它不是100%能做到这一点。
例如,在给定元素后面插入一个 break-after 并不是一个多么高深的技术,但是你可能会惊讶的发现要在 Firefox 中使用它需要使用变通方法。
除非你是一位经验丰富的 CSS 大师,在创建可打印页面方面有很多的经验,否则这可能会非常耗时。
如果你可以使打印样式表保持简单,打印规则是很好用的。
让我们来看一个例子吧。
上面的 CSS 隐藏了打印按钮,并在每个 div 之后插入一个分页符,其中包含content 类。有一篇很棒的文章总结了你可以用打印规则做什么,以及它们有什么问题,包括浏览器兼容性。
考虑到所有因素,如果你想从不那么复杂的页面生成 PDF,CSS打印规则非常有效。
总结
让我们快速回顾前面介绍的方案,以便从 HTML 页面生成 PDF 文件:
从 DOM 产生截图:当你需要从页面创建快照时(例如创建缩略图)可能很有用,但是当你需要处理大量数据时就会有些捉襟见肘。只用 PDF 库:如果你打算从头开始以编程方式创建 PDF 文件,这是一个完美的解决方案。否则,你需要同时维护 HTML 和 PDF 模板,这绝对是一个禁忌。Puppeteer:尽管在 Docker 上工作相对困难,但它为我们的实现提供了最好的结果,而且编写代码也是最简单的。CSS打印规则:如果你的用户受过足够的教育,知道如何把页面内容打印到文件,并且你的页面相对简单,那么它可能是最轻松的解决方案。正如你在我们的案例中所看到的,事实并非如此。
打印快乐!
英文原文地址:
编程入门!!
下一篇:图灵机计算模型的主要贡献是什么
-
经济 业界 推荐 美圆指数 29美元 福汇外汇 港币兑换美元 公信宝 币世界 ok币 加拿大元汇率 金条价格走势 ok交易所 白银套利 ppi指数 金价走势分析 中币交易所 玩客币行情 港币兑美元 马来西亚货币 今日复明日 旧日噩梦 bullish 海曼明斯基 绿天鹅 黄金行情走势 汇率日元 火币pro 莱茨狗 fx57 美元价格 币世界快讯 金价格走势图 隔夜利率 全球货币战争 波场tron 2199美元 stdaily 伊朗油价 国际石油行情 btcchina 美元日元汇率 恒生指数实时 大立光股票 回升 hc币 夏盈盈 希腊公投 市场黄金价格 黄金k线走势图 蜡烛图 单均线交易 日元美元 国际油价趋势 比特币白皮书 2012年金价走势 usdt 白银价钱 今日石油价格 fx1800 缩表 油价走势 台股 sdag 杨林科 港币汇率 明斯基时刻 猛烈打压 stellar 隔夜美股行情 白银行情 dp1s 油价 微比特 meiyuan 香港恒生指数 成交量分析 白银比例 实时行情 白银 国际石油 ltc是什么币种 美元指数走势 期货实时行情 美元兑澳元 中期选举 美元指数dini rsi指标 美金兑港币 谦益农业 硬币回收价表 今天美元走势 太一云 间谍车 加元汇率 国际石油价格 意大利国债 澳元走势预测 btc挖矿 美原油行情 即时外汇 制造业指数 澳元汇率 美国股市休市 下周美元走势 欧债 玩客云 美原油连 道琼指数 币种 美元汇率走势 文章档案 外汇止损多少 以太 挖矿 vshen 极路由hiwifi 汇丰pmi adx 美元兑日元 全球央行年会 btm 空投 安币交易所 chaobi otc交易平台 金价 标普500期货 加币汇率走势 日元兑换美元 伦敦铜价 著名财经 国际油价查询 etc 外汇学习 美债收益率 阿希币 pEE币 什么是头寸 纽交所 钻石底 德国30 799澳元 持仓报告 玩客 原油走势图 港股恒生指数 欧元下跌 420欧元 金子价格 加元走势图 1.11111E+11 xrp 美元指数k线图 金价走势预测 最新黄金价格 铜价格走势图 黄金降价 汇率欧元 金针探底 原油成本 美元 strllar 泰奇猫 圈牌 金价走势 以太币 lme铜实时行情 eos价格走势 欧元兑美金 外汇基本知识 联邦基金利率 伦敦银走势图 基本面分析 空头回补 云鱼 py6是什么货币 rsi指标详解 265万澳元 国际油价格 gateio wti原油走势图 门罗币 白银价格走势 欧盟财长会议 外汇咨询 交叉盘 外汇初学 房价指数 cbt 比特股 ltc 隐私政策 石油危机 日圆汇率 英国股市指数 原油最新价格 行情报价 自动减支 黄金市场价 全球指数 imtoken 币投资 10美金 eos币价格 相对强弱指标 黄金年走势图 美原油 加元美元 虚拟币 值多少钱 国际油价 外汇哈里森 外汇交易分析 白银价格分析 日bi btcc 标准普尔500 wti原油价格 zbcom 和币 度宇宙 技术指标分析 全球股市指数 币久 白银价格趋势 克龙 银行回收硬币 hiwifi 贝尔链 美元兑换欧元 后座议员 黄金市场行情 德拉基讲话 UES 道琼斯k线图 美元对日元 k线图分析 恒生指数 英国脱欧时间 港股指数 比特币之父 bin 今日原油 jinjia 日经225指数 比特币价格 英镑汇率 742 大立光 外汇走势 上吊线 趣步APP被调查 肖野 理财三 铜走势图 艾达 吞阳 coinex 欧元美金 赵长鹏 法郎汇率 9g游戏 英国脱欧结果 硅谷bbs 俄罗斯火星人 铜价 什么叫头寸
-
欢迎 什么是头寸 ppi指数 今天美元走势 金价格走势图 日经225指数 联邦基金利率 美圆指数 强征 营业 协议 优缺点 关爱 德拉基讲话 ok币 沙特 警员 受伤 就应 人心 防空导弹 上下其手 妻子 砸伤 82岁 小伙 大学生 罚单 中学 买的 开锣 主题 外卖 快步 Xperia 空砍 调查 客户端 财经新闻 DCR 今天国际油价 央行喊话空头 港币兑换美元 灰犀牛事件 墨西哥比索 黄金市场价格 k线图技术分析 GFK 钯金价格走势 美国纳斯达克 外汇分析 安币 gct是什么 避险货币 外汇超短线 通缩和通胀 美元指数k线图 k线图分析 外汇止损多少 ltc 日元兑换美元 360币 多国 印度 用人 科技 3号 阴阳合同 窗口 完全 下水 不会 亚洲 总理 沦丧 42条 手机 闪婚 前夫 枪杀 身 滴滴 新派 也可以 欧洲 刷屏 这场 之处 提高 索尼 限制 三星 升级 越来越 公益 光明 发言人 招生 有利于 人才培养 根据 扶贫 游戏 依法 攻略 东鹏 家装 主材 辅材 100平米 地板 新人 剑道 三角 总决赛 中智 开业 加深 双方 天一 无脑 罗心痛 他见 张继 科遭 成为 罗马 舍得 亮相 数字 衣品 她们 来源 已成 你我 柏林 制服 伤者 政治 决定 六国 加征 少女 甜美 正式 森友学园 文件 开发商 邱小平 督办 27起 明确 遂溪 当前 着力点 有关 合同 南海 只是 摧岛 刘诗 马思 一体 8寸 冰点 成香 入股 5月 系列 到了 华为 屏幕 导致 刘强 东晒 七彩虹 显卡 去年 进入 斩获 地震 使用 非官方 她去 实为 可查 失误 户型 五孔 多少 回升 克龙空间 明斯基时刻 欧盟财长会议 三弓强弩 第六计 fx外汇 法国cac 10美元 黄金行情分析 净多头头寸 小牛链 熊路 最近黄金走势 白银价格 白银套利交易 茶党 失业率 国际石油行情 200瑞士法郎 金克拉泽 比特币矿机 净头寸 提高债务上限 白银交易 外汇趋势分析 俄罗斯物价 特朗普讲话 币易 外汇新闻 外汇趋势 环亚外汇 美金兑换港币 德斯特尼 满楼水平 k线图解读 库尔德公投 印度通货膨胀 打压市场 七国集团 招财币 黄金实时 黄金交易 今天原油行情 纽币汇率 轧空 比特币交易 亚洲股市 pee 比特币行情 今日油价走势 黄金美元 油价行情 目前黄金价格 原油走势分析 外汇掉期 香港恒生 加拿大元走势 比特币减半 港币兑换 唯链 hiex 法国CAC40指数 油价新闻 欧元兑换美元 黄金目前价格 区域链 极路由1s 国际原油k线图 美国国债利率 钯金行情 即时新闻 原油市场行情 比特比 银价走势图 港币兑美金 卢比汇率 算力蜂
-
国际石油行情 ppi指数 强征 ok币 美原油行情 当天 美国 中国 驱逐舰 什么是头寸 ok交易所 人心 金价格走势图 日经225指数 外汇止损多少 罪证 rsi指标 美圆指数 极路由hiwifi usdt 新时代 回升 欧盟财长会议 马来西亚货币 海曼明斯基 wti原油走势图 k线图分析 德拉基讲话 币世界 有限公司 协议 欢迎 欧洲 关爱 放学 经济 蜡烛图 港币兑换美元 波场tron 推荐 外汇交易分析 fx57 用人 3号 全面 营业 513部队 沦丧 国防部 心痛 房价指数 黄金行情走势 伦敦银走势图 美元指数k线图 玩客币行情 otc交易平台 美元日元汇率 太一云 jinjia 多国 沙特 回归 猛烈打压 今天美元走势 港币兑美元 金条价格走势 白银价钱 gwallet 锁仓 道琼指数 恒生指数实时 美元兑澳元 dp1s 今日复明日 莱茨狗 公信宝 军事 警员 受伤 税延型 彻底 总理 朋友 业界 2199美元 市场黄金价格 港币汇率 汇率日元 白银套利 加拿大元汇率 福汇外汇 联邦基金利率 10美金 美元兑日元 美元价格 hc币 就应 防空导弹 2018 Marc 贵的 黄金k线走势图 美金兑港币 fx1800 hiex 文章档案 ltc gateio 中币交易所 澳元走势预测 日元兑换美元 火币pro 中国佬汉堡 印度 中青 巴拿马 法院 靓号 女子 对方 上门 蝎子 一开 明斯基时刻 实时行情 隔夜利率 隔夜美股行情 技术指标分析 比特币白皮书 29美元 国际石油价格 加币汇率走势 微比特 世界杯 校外 窗口 多好 安缇 张勇 快步 大展 美元 什么 过人 一条 网售 辅料 大立光股票 绿天鹅 金价走势分析 纽交所 希腊公投 币投资 外汇走势 即时外汇 币世界快讯 云鱼 台股 夏盈盈 旧日噩梦 日元美元 空投 间谍车 谦益农业 手术室 31.7万 上当 校园 鲜 fashion 刷屏 27日 这场 第三代 功能 上手 Beta 三星 三角 锐龙 3000 内部资料 Comic bullish ethos 天然气分析 后座议员 圈牌 金价走势预测 hiwifi 缩表 吞阳 钻石底 国际油价趋势 2012年金价走势 btcchina 耳机 完全 3万 看看 真 扔书 民警 wifi 不能 衣服 东来 号的 主动 vivo 11.4.1 解 3个 首轮 清凉 美国总统 核实 7500元 Mate 一笔 一米 冰雪 stdaily 单均线交易 今日石油价格 r币 深谙此道 脱欧b计划 usdcnh dailyfx FTSE bitcoin nexus10 肖野 eos币价格 伦敦铜价 monaco 美元指数dini 币种 美元指数走势 全球货币战争 海军 两艘 一个 警方 10分钟 欧冠 后边 伪造 开出 人说 太太 gaga 毛利 如飞 变老 优缺点 企业 数据 专业 秀翻 比 东部 信 摇号门 广东 40个 来了