怎样使用Node.js生成PDF?

Puppeteer适合HTML转PDF因能真实渲染网页内容,支持动态加载、高保真输出;pdf-lib适合代码直接生成或修改PDF,性能更高但布局需手动计算。

怎样使用node.js生成pdf?

要在Node.js中生成PDF,最直接有效的方式是利用现有的库。对于需要将HTML内容转换为PDF的场景,我个人通常会选择Puppeteer,它通过控制一个无头浏览器来渲染网页并将其保存为PDF,这能最大程度地保留原始网页的布局和样式。而如果你的需求是纯粹地从代码层面构建PDF,例如绘制图形、插入文本等,那么像

pdf-lib

这样的库会更合适。

解决方案

如果你想把一个网页或一段HTML代码转换成PDF,Puppeteer无疑是目前最强大、最灵活的选项之一。它本质上是Google Chrome或Chromium的Node.js API,这意味着你可以用它来做任何浏览器能做的事情,包括生成高质量的PDF。

以下是一个基本的Puppeteer生成PDF的流程和代码示例:

安装Puppeteer:

npm install puppeteer

编写生成PDF的代码:

const puppeteer = require('puppeteer');const path = require('path');async function generatePdfFromHtml(htmlContent, outputPath) {    let browser;    try {        browser = await puppeteer.launch({            headless: true, // 在后台运行浏览器,不显示UI            args: ['--no-sandbox', '--disable-setuid-sandbox'] // 某些环境可能需要        });        const page = await browser.newPage();        // 设置页面内容为HTML字符串        await page.setContent(htmlContent, {            waitUntil: 'networkidle0' // 等待网络空闲,确保所有资源加载完成        });        // 或者,如果你想从一个URL生成PDF        // await page.goto('https://example.com', {        //     waitUntil: 'networkidle0'        // });        await page.pdf({            path: outputPath,            format: 'A4',            printBackground: true, // 打印背景颜色和图片            margin: {                top: '20mm',                right: '20mm',                bottom: '20mm',                left: '20mm'            },            // displayHeaderFooter: true, // 是否显示页眉页脚            // headerTemplate: '页眉', // 页眉HTML模板            // footerTemplate: '页脚', // 页脚HTML模板        });        console.log(`PDF已成功生成到: ${outputPath}`);    } catch (error) {        console.error('生成PDF时出错:', error);    } finally {        if (browser) {            await browser.close();        }    }}// 示例用法const html = `                    我的报告                    body { font-family: 'Arial', sans-serif; margin: 0; padding: 0; color: #333; }            .container { width: 800px; margin: 50px auto; border: 1px solid #eee; padding: 30px; box-shadow: 0 0 10px rgba(0,0,0,0.05); }            h1 { color: #0056b3; text-align: center; }            p { line-height: 1.6; }            .footer { text-align: center; margin-top: 50px; font-size: 0.8em; color: #666; }            /* 打印样式 */            @media print {                .container { box-shadow: none; border: none; }                /* 强制在某个元素前分页 */                .new-page { page-break-before: always; }            }                        

年度总结报告

这是一段关于今年工作成果的介绍性文字。我们取得了显著的进步,特别是在产品研发和市场拓展方面。

本报告将详细阐述各项指标、挑战以及未来的展望。

关键成就

  • 用户增长率达到20%
  • 新产品发布市场反响良好
  • 团队协作效率提升15%

数据分析

通过对用户行为数据的深入分析,我们发现了一些新的趋势,这将指导我们下一阶段的策略调整。

@@##@@
`;const outputPath = path.join(__dirname, 'my_report.pdf');generatePdfFromHtml(html, outputPath);

这段代码展示了如何启动一个无头浏览器实例,加载HTML内容,然后调用

page.pdf()

方法将其保存为PDF文件。你可以通过

page.pdf()

的选项来控制PDF的格式、边距、是否打印背景、页眉页脚等。

为什么选择Puppeteer来生成PDF?它有哪些优势?

对我来说,选择Puppeteer生成PDF,最核心的原因就是它的“所见即所得”能力。我们都知道,网页开发已经非常成熟,用HTML、CSS和JavaScript来构建复杂、美观的布局简直是家常便饭。如果一个PDF只是要把这些已经设计好的内容呈现出来,Puppeteer简直是完美的选择。

它的优势非常明显:

真实渲染环境:Puppeteer背后跑的是一个完整的Chromium浏览器,这意味着它能像用户浏览器一样解析和渲染HTML、CSS和JavaScript。那些复杂的CSS布局、动画效果(虽然PDF是静态的,但渲染时会执行JS)、外部字体、图片等,都能被准确地捕获并呈现在PDF中。这对于生成包含图表、复杂表格、动态内容报告的PDF特别有用。高保真度:与一些基于模板或DOM解析的PDF库不同,Puppeteer生成的PDF几乎就是网页的快照。你不需要担心CSS属性不被支持,或者JavaScript渲染的内容丢失。我个人在做一些客户报告、发票或者在线简历生成时,发现它能完美复刻网页版的设计,省去了大量的样式适配工作。动态内容支持:如果你的网页内容是动态加载的(比如通过AJAX获取数据后渲染),Puppeteer可以在这些内容加载并渲染完成后再进行截图或PDF生成。

waitUntil: 'networkidle0'

这样的选项就是为此服务的。易于调试:由于它基于Chrome,你可以选择以非无头模式运行Puppeteer (

headless: false

),直接看到浏览器窗口,甚至打开开发者工具进行调试,这在排查布局问题时非常方便。功能强大:除了生成PDF,Puppeteer还能做很多其他事情,比如网页截图、自动化测试、爬虫等,这使得它成为一个多功能的工具。

当然,它也有一些缺点,比如启动一个浏览器实例会有一定的资源开销,但对于大多数服务器端生成PDF的场景,这点开销是完全可以接受的。

生成复杂PDF时,如何处理样式、分页和字体问题?

在实际操作中,尤其面对复杂的报告或文档,样式、分页和字体处理是生成高质量PDF的关键,也常常是让人头疼的地方。

样式处理:Puppeteer能够很好地处理CSS,但你需要记住,PDF是打印介质,所以要充分利用CSS的

@media print

规则。我通常会这样做:

打印专用CSS:在你的样式表中,专门为

@media print

定义一套规则。比如,隐藏掉页面上的导航栏、按钮等在打印时不需要的元素,调整字体大小以适应打印,或者为表格添加更清晰的边框。单位选择:在打印样式中,使用

mm

cm

in

pt

等物理单位比

px

更可靠,因为它们在打印时有固定的物理尺寸。避免绝对定位滥用:虽然绝对定位在网页布局中很常见,但在打印时可能会导致内容溢出或重叠。尽量使用流式布局或Flexbox/Grid来构建主要结构。背景打印:确保

page.pdf()

选项中的

printBackground: true

设置为真,否则背景颜色和图片可能不会被打印出来。

分页控制:这是PDF生成中最常见的挑战之一。没人喜欢内容被截断在两页之间。CSS3提供了一些非常有用的属性来控制分页:

page-break-before: always;

:强制在元素之前分页。这对于确保每个新章节或大标题都从新页开始非常有用。

page-break-after: always;

:强制在元素之后分页。

page-break-inside: avoid;

:尽量避免在元素内部(例如一个完整的表格行、一个图片和其标题组成的

div

)分页。这对于保持内容的完整性非常重要。

orphans

widows

:这两个CSS属性可以控制段落中,一页顶部或底部至少保留的行数,避免出现孤行或寡行。Puppeteer的页眉页脚:如果你需要统一的页眉页脚(比如页码、公司Logo),Puppeteer的

displayHeaderFooter

headerTemplate

footerTemplate

选项非常方便。它们接受HTML字符串,你可以用CSS来控制它们的样式和位置,甚至用

标签配合

pageNumber

totalPages

来显示页码。

字体问题:字体是另一个可能导致PDF看起来与预期不符的问题。

Web字体嵌入:如果你使用了非系统默认字体(比如Google Fonts),确保它们被正确地加载和嵌入到HTML中。Puppeteer会等待这些字体加载完成。在CSS中,使用

@font-face

规则并提供字体文件的URL,或者直接通过


标签引入。字体子集化:在某些情况下,为了减小PDF文件大小,PDF生成器可能会对字体进行子集化(只嵌入实际使用的字符)。这通常是自动的,但如果遇到字符显示问题,需要检查字体文件是否完整或是否被正确引用。Fallback字体:在CSS中定义一个字体栈,比如

font-family: 'MyCustomFont', Arial, sans-serif;

,这样即使自定义字体加载失败,也有一个可靠的系统字体作为备选。

处理这些问题时,我经常会采取迭代的方式:先生成一个初稿,然后根据PDF的实际效果调整HTML/CSS,再生成,直到满意为止。

除了Puppeteer,还有哪些Node.js库可以用于PDF生成?它们适用于哪些场景?

虽然Puppeteer是我处理HTML到PDF转换的首选,但在某些特定场景下,其他Node.js库可能更合适,或者说,它们解决的是不同类型的问题。

pdf-lib

(或

jsPDF

)

特点:这些库不依赖浏览器渲染,而是直接通过JavaScript代码操作PDF文档的底层结构。你可以用它们来绘制图形、添加文本、插入图片、创建表单字段、修改现有PDF等。它们更像是PDF的“画板”和“编辑器”。适用场景纯代码生成PDF:当你不需要将HTML转换为PDF,而是希望完全通过编程来构建一个PDF时,比如生成简单的收据、证书、图表(数据驱动的图形绘制)、或者需要高度定制化PDF布局的场景。修改现有PDF:例如,你有一个PDF模板,需要动态地在特定位置填充文本或图片,

pdf-lib

在这方面非常强大。性能敏感:对于非常简单的PDF生成,或者在资源受限的环境中,避免启动一个完整的浏览器实例可以节省大量内存和CPU。个人看法:我用

pdf-lib

比较多,因为它在处理二进制PDF文件和更底层的PDF结构方面表现出色。比如,我曾用它来给用户上传的PDF文件添加水印,或者合并多个PDF文档。它提供了对PDF内容的精细控制,但缺点是,如果你想实现复杂的布局,需要手动计算每个元素的位置,这比写HTML/CSS要繁琐得多。

html-pdf

特点:这是一个相对较老的库,它使用PhantomJS(一个无头Webkit浏览器)或Headless Chrome来将HTML转换为PDF。它的API比Puppeteer更简洁,但功能相对较少,且PhantomJS已经不再维护。适用场景简单HTML到PDF转换:对于非常简单的HTML结构,没有复杂JavaScript交互的页面,

html-pdf

可能是一个轻量级的选择。遗留项目:如果你的项目已经在使用它,并且运行良好,可能没有必要立即迁移。个人看法:我个人现在很少推荐

html-pdf

,因为它依赖的PhantomJS已经过时,而其Headless Chrome的集成也不如Puppeteer那么完善和灵活。如果非要HTML转PDF,我几乎总是直接上Puppeteer,因为它更现代,社区活跃,且功能更强大。

总的来说,选择哪个库,关键在于你的具体需求。如果你的内容已经以HTML形式存在,并且需要高保真度的视觉呈现,Puppeteer是毋庸置疑的首选。而如果你需要从零开始构建PDF内容,或者对现有PDF进行操作,那么像

pdf-lib

这样的底层PDF操作库会更有效率。没有绝对的“最好”,只有最适合当前任务的工具。

示例图片

以上就是怎样使用Node.js生成PDF?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1518754.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
JavaScript 中将整数转换为保留两位小数的字符串
上一篇 2025年12月20日 11:50:51
Node.js中如何创建子进程?
下一篇 2025年12月20日 11:51:01

相关推荐

  • composer require-dev和require有什么不同_Composer Require与Require-Dev区别解析

    require用于声明项目运行必需的依赖,如框架、数据库组件和第三方SDK,这些包会随项目部署到生产环境;2. require-dev用于声明仅在开发和测试阶段需要的工具,如PHPUnit、PHPStan、Faker等,不会默认部署到生产环境;3. 安装时composer install根据环境决定…

    2026年5月10日
    1000
  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    100
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 利用海象运算符简化条件赋值:Python教程与最佳实践

    本文旨在探讨Python中海象运算符(:=)在条件赋值场景下的应用。通过对比传统if/else语句与海象运算符,以及条件表达式,分析海象运算符在简化代码、提高可读性方面的优势与局限性。并通过具体示例,展示如何在列表推导式等场景下合理使用海象运算符,同时强调其潜在的复杂性及替代方案,帮助开发者更好地掌…

    2026年5月10日
    100
  • Debian syslog性能优化技巧有哪些

    提升Debian系统syslog (通常基于rsyslog)性能,关键在于精简配置和高效处理日志。以下策略能有效优化日志管理,提升系统整体性能: 精简配置,高效加载: 在rsyslog配置文件中,仅加载必要的输入、输出和解析模块。 使用全局指令设置日志级别和格式,避免不必要的处理。 自定义模板: 创…

    2026年5月10日
    000
  • 怎么在PHP代码中实现图片上传功能_PHP图片上传功能实现与安全处理教程

    首先创建含enctype的HTML表单,再用PHP接收文件,检查目录、移动临时文件,验证类型与大小,生成唯一文件名,并调整php.ini限制以确保上传成功。 如果您尝试在PHP项目中添加图片上传功能,但服务器无法正确接收或保存文件,则可能是由于表单配置、文件处理逻辑或安全限制的问题。以下是实现该功能…

    2026年5月10日
    100
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • HTML如何隐藏滚动条或去除滚动条

    滚动条可以存在也可以不存在,本文主要介绍了html 隐藏滚动条和去除滚动条的方法的相关资料,大家一起来学习一下html隐藏滚动条或去除滚动条的方法吧。 1. html 标签加属性 XML/HTML Code复制内容到剪贴板 2.body中加入以下代码 立即学习“前端免费学习笔记(深入)”; html…

    用户投稿 2026年5月10日
    100
  • Golang gRPC流式请求异常处理

    在Golang的gRPC流式通信中,必须通过context.Context处理异常。应监听上下文取消或超时,及时释放资源,设置合理超时,避免连接长时间挂起,并在goroutine中通过context控制生命周期。 在使用 Golang 和 gRPC 实现流式通信时,异常处理是确保服务健壮性的关键部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • css max-height属性怎么用

    max-height 属性设置元素的最大高度。 说明 该属性值会对元素的高度设置一个最高限制。因此,元素可以比指定值矮,但不能比其高。不允许指定负值。 注意:max-height 属性不包括外边距、边框和内边距。 立即学习“前端免费学习笔记(深入)”; 值描述none 默认。定义对元素被允许的最大高…

    2026年5月10日
    100
  • vscode上怎么运行html_vscode上运行html步骤【指南】

    首先保存文件为.html格式,再通过浏览器或Live Server插件打开预览;推荐安装Live Server实现本地服务器运行与实时刷新,提升开发体验。 在 VS Code 上运行 HTML 文件并不需要复杂的配置,只需几个简单步骤即可预览页面效果。VS Code 本身是一个代码编辑器,不直接运行…

    2026年5月10日
    100
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 页面中文本域的值怎么设置

    标签定义多行的文本输入控件。 文本区中可容纳无限数量的文本,其中的文本的默认字体是等宽字体(通常是 Courier)。 可以通过 cols 和 rows 属性来规定 textarea 的尺寸,不过更好的办法是使用 CSS 的 height 和 width 属性。 注释:在文本输入区内的文本行间,用 …

    2026年5月10日
    000
  • 《魔兽世界》将于6月11日开启国服回归技术测试

    《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试

    《%ign%ignore_a_1%re_a_1%》官方宣布,将于6月11日开启国服回归技术测试,时间为7天,并称可以在6月内正式开服,玩家们可以访问官网下载战网客户端并预下载“巫妖王之怒”客户端,技术测试详情见下图。 WordAi WordAI是一个AI驱动的内容重写平台 53 查看详情 以上就是《…

    2026年5月10日 用户投稿
    200
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信