HTML을 PDF로 변환하는 방법은 무엇입니까? 방법 소개
이 기사에서는 Node.js, Puppeteer, 헤드리스 Chrome 및 Docker를 사용하여 복잡한 스타일의 React 페이지에서 PDF 문서를 생성하는 방법을 보여 드리겠습니다.
관련 추천: "nodejs Tutorial"
배경: 몇 달 전 한 고객이 사용자가 React 페이지 콘텐츠를 PDF 형식으로 얻을 수 있는 기능을 개발해 달라고 요청했습니다. 이 페이지는 기본적으로 많은 SVG가 포함된 환자 사례에 대한 보고서 및 데이터 시각화입니다. 레이아웃을 조작하고 HTML 요소의 일부 재배열을 수행하기 위한 특별한 요청도 있습니다. 따라서 PDF에는 원본 React 페이지와 다른 스타일과 추가 콘텐츠가 있어야 합니다.
이 작업은 간단한 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 코드> <code>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
const puppeteer = require('puppeteer') async function printPDF() { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.goto('https://blog.risingstack.com', {waitUntil: 'networkidle0'}); const pdf = await page.pdf({ format: 'A4' }); await browser.close(); return pdf })
html2canvas
의 onclone
메소드를 참고하세요. 스크린샷을 찍기 전에 DOM을 조작해야 할 때(예: 인쇄 버튼 숨기기) 매우 편리합니다. 나는 이 패키지를 사용하는 많은 프로젝트를 보았습니다. 하지만 안타깝게도 백엔드에서 PDF 생성을 수행해야 하기 때문에 이는 우리가 원하는 것이 아닙니다. 옵션 2: 그냥 PDF 라이브러리를 사용하세요 🎜🎜🎜NPM에는 jsPDF(위에서 언급한 대로) 또는 PDFKit🎜. 문제는 이러한 라이브러리를 사용하려면 페이지를 재구성해야 한다는 것입니다. PDF 템플릿과 React 페이지 모두에 모든 후속 변경 사항을 적용해야 하므로 유지 관리성이 확실히 손상됩니다. 🎜🎜아래 코드를 참고해주세요. PDF 문서를 직접 수동으로 작성해야 합니다. DOM을 살펴보고 각 요소를 찾아 PDF 형식으로 변환해야 하는데 이는 지루한 작업입니다. 더 쉬운 방법을 찾아야 합니다. 🎜await page.type('#email', process.env.PDF_USER)
await page.type('#password', process.env.PDF_PASSWORD)
await page.click('#submit')
로그인 후 복사로그인 후 복사🎜이 코드 조각은 PDFKit 문서에서 가져온 것입니다. 그러나 기존(계속 변경되는) HTML 페이지를 변환하는 대신 PDF 파일을 직접 생성하는 것이 목표라면 여전히 유용할 수 있습니다. 🎜🎜최종 솔루션 3: Node.js 기반 Puppeteer 및 헤드리스 Chrome🎜🎜🎜 인형사🎜? 문서 내용은 다음과 같습니다. 🎜Puppeteer는 DevTools 프로토콜에서 Chrome 또는 Chromium을 제어하기 위한 고급 API를 제공하는 노드 라이브러리입니다. Puppeteer는 기본적으로 헤드리스 모드에서 Chrome 또는 Chromium을 실행하지만 전체(비헤드리스) 모드에서 실행되도록 구성할 수도 있습니다.
🎜기본적으로 Node.js에서 실행되는 브라우저입니다. 문서를 읽으면 가장 먼저 언급되는 것은 Puppeteer를 사용하여 페이지의 🎜스크린샷과 PDF를 생성🎜할 수 있다는 것입니다. 훌륭한! 이것이 바로 우리가 원하는 것입니다. 🎜🎜먼저 npmi i puppeteer
를 사용하여 Puppeteer를 설치하고 기능을 구현하세요. 🎜await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })
로그인 후 복사로그인 후 복사🎜이것은 URL로 이동하여 사이트의 PDF 파일을 생성하는 간단한 기능입니다. 🎜🎜먼저 브라우저를 시작한 다음(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 :
const browser = await puppeteer.launch({
headless: true,
args: ['--disable-dev-shm-usage']
});
로그인 후 복사否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。
方案 3 + 1:CSS 打印规则
可能有人认为从开发人员的角度来看,简单地使用 CSS 打印规则很容易。没有 NPM 模块,只有纯 CSS。但是在跨浏览器兼容性方面,它的表现如何呢?
在选择 CSS 打印规则时,你必须在每个浏览器中测试结果,以确保它提供的布局是相同的,并且它不是100%能做到这一点。
例如,在给定元素后面插入一个 break-after 并不是一个多么高深的技术,但是你可能会惊讶的发现要在 Firefox 中使用它需要使用变通方法。
除非你是一位经验丰富的 CSS 大师,在创建可打印页面方面有很多的经验,否则这可能会非常耗时。
如果你可以使打印样式表保持简单,打印规则是很好用的。
让我们来看一个例子吧。
@media print {
.print-button {
display: none;
}
.content div {
break-after: always;
}
}
로그인 후 복사上面的 CSS 隐藏了打印按钮,并在每个 div
之后插入一个分页符,其中包含content
类。有一篇很棒的文章总结了你可以用打印规则做什么,以及它们有什么问题,包括浏览器兼容性。
考虑到所有因素,如果你想从不那么复杂的页面生成 PDF,CSS打印规则非常有效。
总结
让我们快速回顾前面介绍的方案,以便从 HTML 页面生成 PDF 文件:
-
DOM에서 스크린샷 생성: 페이지에서 스냅샷을 생성해야 할 때(예: 썸네일 생성) 유용할 수 있지만, 대량의 데이터를 처리해야 할 경우에는 무리가 될 수 있습니다.
-
PDF 라이브러리만: 처음부터 프로그래밍 방식으로 PDF 파일을 생성하려는 경우 이것이 완벽한 솔루션입니다. 그렇지 않으면 HTML과 PDF 템플릿을 모두 유지해야 하는데 이는 절대 금물입니다.
-
Puppeteer: Docker에서 작업하는 것은 상대적으로 어렵지만 구현에 가장 좋은 결과를 제공했고 코딩하기가 가장 쉬웠습니다.
-
CSS 인쇄 규칙: 사용자가 페이지 내용을 파일로 인쇄하는 방법을 충분히 교육받았고 페이지가 상대적으로 단순하다면 이것이 아마도 가장 쉬운 솔루션일 것입니다. 우리의 경우에서 볼 수 있듯이 그렇지 않습니다.
즐거운 인쇄 되세요!
영어 원본 주소: https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/
더 많은 프로그래밍 관련 지식을 보려면 다음을 방문하세요: 프로그래밍 입문! !
위 내용은 HTML을 PDF로 변환하는 방법은 무엇입니까? 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!
await page.type('#email', process.env.PDF_USER) await page.type('#password', process.env.PDF_PASSWORD) await page.click('#submit')
Puppeteer는 DevTools 프로토콜에서 Chrome 또는 Chromium을 제어하기 위한 고급 API를 제공하는 노드 라이브러리입니다. Puppeteer는 기본적으로 헤드리스 모드에서 Chrome 또는 Chromium을 실행하지만 전체(비헤드리스) 모드에서 실행되도록 구성할 수도 있습니다.🎜기본적으로 Node.js에서 실행되는 브라우저입니다. 문서를 읽으면 가장 먼저 언급되는 것은 Puppeteer를 사용하여 페이지의 🎜스크린샷과 PDF를 생성🎜할 수 있다는 것입니다. 훌륭한! 이것이 바로 우리가 원하는 것입니다. 🎜🎜먼저
npmi i puppeteer
를 사용하여 Puppeteer를 설치하고 기능을 구현하세요. 🎜await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })
设置 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 :
const browser = await puppeteer.launch({ headless: true, args: ['--disable-dev-shm-usage'] });
否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。
方案 3 + 1:CSS 打印规则
可能有人认为从开发人员的角度来看,简单地使用 CSS 打印规则很容易。没有 NPM 模块,只有纯 CSS。但是在跨浏览器兼容性方面,它的表现如何呢?
在选择 CSS 打印规则时,你必须在每个浏览器中测试结果,以确保它提供的布局是相同的,并且它不是100%能做到这一点。
例如,在给定元素后面插入一个 break-after 并不是一个多么高深的技术,但是你可能会惊讶的发现要在 Firefox 中使用它需要使用变通方法。
除非你是一位经验丰富的 CSS 大师,在创建可打印页面方面有很多的经验,否则这可能会非常耗时。
如果你可以使打印样式表保持简单,打印规则是很好用的。
让我们来看一个例子吧。
@media print { .print-button { display: none; } .content div { break-after: always; } }
上面的 CSS 隐藏了打印按钮,并在每个 div
之后插入一个分页符,其中包含content
类。有一篇很棒的文章总结了你可以用打印规则做什么,以及它们有什么问题,包括浏览器兼容性。
考虑到所有因素,如果你想从不那么复杂的页面生成 PDF,CSS打印规则非常有效。
总结
让我们快速回顾前面介绍的方案,以便从 HTML 页面生成 PDF 文件:
- DOM에서 스크린샷 생성: 페이지에서 스냅샷을 생성해야 할 때(예: 썸네일 생성) 유용할 수 있지만, 대량의 데이터를 처리해야 할 경우에는 무리가 될 수 있습니다.
- PDF 라이브러리만: 처음부터 프로그래밍 방식으로 PDF 파일을 생성하려는 경우 이것이 완벽한 솔루션입니다. 그렇지 않으면 HTML과 PDF 템플릿을 모두 유지해야 하는데 이는 절대 금물입니다.
- Puppeteer: Docker에서 작업하는 것은 상대적으로 어렵지만 구현에 가장 좋은 결과를 제공했고 코딩하기가 가장 쉬웠습니다.
- CSS 인쇄 규칙: 사용자가 페이지 내용을 파일로 인쇄하는 방법을 충분히 교육받았고 페이지가 상대적으로 단순하다면 이것이 아마도 가장 쉬운 솔루션일 것입니다. 우리의 경우에서 볼 수 있듯이 그렇지 않습니다.
즐거운 인쇄 되세요!
영어 원본 주소: https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/
더 많은 프로그래밍 관련 지식을 보려면 다음을 방문하세요: 프로그래밍 입문! !
위 내용은 HTML을 PDF로 변환하는 방법은 무엇입니까? 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











HTML의 테이블 테두리 안내. 여기에서는 HTML의 테이블 테두리 예제를 사용하여 테이블 테두리를 정의하는 여러 가지 방법을 논의합니다.

HTML 여백-왼쪽 안내. 여기에서는 HTML margin-left에 대한 간략한 개요와 코드 구현과 함께 예제를 논의합니다.

HTML의 Nested Table에 대한 안내입니다. 여기에서는 각 예와 함께 테이블 내에 테이블을 만드는 방법을 설명합니다.

HTML 테이블 레이아웃 안내. 여기에서는 HTML 테이블 레이아웃의 값에 대해 예제 및 출력 n 세부 사항과 함께 논의합니다.

HTML 입력 자리 표시자 안내. 여기서는 코드 및 출력과 함께 HTML 입력 자리 표시자의 예를 논의합니다.

HTML 순서 목록에 대한 안내입니다. 여기서는 HTML Ordered 목록 및 유형에 대한 소개와 각각의 예에 대해서도 설명합니다.

HTML에서 텍스트 이동 안내. 여기서는 Marquee 태그가 구문과 함께 작동하는 방식과 구현할 예제에 대해 소개합니다.

HTML onclick 버튼에 대한 안내입니다. 여기에서는 각각의 소개, 작업, 예제 및 다양한 이벤트의 onclick 이벤트에 대해 설명합니다.
