찾다
웹 프론트엔드HTML 튜토리얼HTML을 PDF로 변환하는 4가지 방법 소개(코드 포함)

HTML을 PDF로 변환하는 4가지 방법 소개(코드 포함)

Mar 30, 2019 am 10:57 AM
node.jspdf프런트 엔드

이 글에서는 HTML을 PDF로 변환하는 4가지 방법(코드 포함)을 소개합니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

이 기사에서는 Node.js, Puppeteer, 헤드리스 Chrome 및 Docker를 사용하여 복잡한 스타일의 React 페이지에서 PDF 문서를 생성하는 방법을 보여 드리겠습니다.

배경: 몇 달 전 한 고객이 사용자가 React 페이지 콘텐츠를 PDF 형식으로 얻을 수 있는 기능을 개발해 달라고 요청했습니다. 이 페이지는 기본적으로 많은 SVG가 포함된 환자 사례에 대한 보고서 및 데이터 시각화입니다. 레이아웃을 조작하고 HTML 요소의 일부 재배열을 수행하기 위한 특별한 요청도 있습니다. 따라서 PDF에는 원본 React 페이지와 다른 스타일과 추가 콘텐츠가 있어야 합니다.

이 작업은 간단한 CSS 규칙으로 해결하는 것보다 훨씬 복잡하기 때문에 먼저 가능한 구현 방법을 살펴보았습니다. 우리는 3가지 주요 솔루션을 찾았습니다. 이 블로그 게시물은 가능성과 최종 구현 과정을 안내합니다.

클라이언트 측에서 생성되나요, 아니면 서버 측에서 생성되나요?

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')
})
npm install html2canvas jspdf
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()

就这样!

请注意 html2canvas 的 onclone方法。当你在截图之前需要操纵 DOM(例如隐藏打印按钮)时,它是非常方便的。我看到过很多使用这个包的项目。但不幸的是,这不是我们想要的,因为我们需要在后端完成对 PDF 的创建工作。

方案2:只使用 PDF 库

NPM上有几个库,如 jsPDF(如上所述)或PDFKit。他们的问题是,如果我想使用这些库,我将不得不重新调整页面结构。这肯定会损害可维护性,因为我需要将所有后续更改应用到 PDF 模板和 React 页面中。

请看下面的代码。你需要亲自手动创建 PDF 文档。你需要遍历 DOM 并找出每个元素并将其转换为 PDF 格式,这是一项繁琐的工作。必须找到一个更简单的方法。

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
})

这段代码段来自 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,并实现我们的功能。

await page.type('#email', process.env.PDF_USER)
await page.type('#password', process.env.PDF_PASSWORD)
await page.click('#submit')

这是一个简单的功能,可导航到 URL 并生成站点的 PD F文件。

首先,我们启动浏览器(仅在 headless 模式下支持 PDF 生成),然后打开新页面,设置视口,并导航到提供的URL。

设置 waitUntil:'networkidle0' 选项意味着当至少500毫秒没有网络连接时,Puppeteer 会认为导航已完成。 (可以从 API docs 获取更多信息。)

之后,我们将 PDF 保存为变量,关闭浏览器并返回 PDF。

注意:page.pdf 方法接收 options끝입니다!

html2canvas의 onclone 방식에 주목해주세요. 스크린샷을 찍기 전에 DOM을 조작해야 할 때(예: 인쇄 버튼 숨기기) 매우 편리합니다. 나는 이 패키지를 사용하는 많은 프로젝트를 보았습니다. 하지만 안타깝게도 백엔드에서 PDF 생성을 수행해야 하기 때문에 이는 우리가 원하는 것이 아닙니다.

옵션 2: PDF 라이브러리만 사용

#🎜🎜# NPM에는 jsPDF(위에서 언급한 대로) 또는 PDFKit과 같은 여러 라이브러리를 사용할 수 있습니다. 문제는 이러한 라이브러리를 사용하려면 페이지를 재구성해야 한다는 것입니다. PDF 템플릿과 React 페이지에 모든 후속 변경 사항을 적용해야 하므로 유지 관리성이 확실히 손상됩니다. #🎜🎜##🎜🎜#아래 코드를 참고해주세요. PDF 문서를 직접 수동으로 작성해야 합니다. DOM을 살펴보고 각 요소를 찾아 PDF 형식으로 변환해야 하는데 이는 지루한 작업입니다. 더 쉬운 방법을 찾아야 합니다. #🎜🎜#
await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })
#🎜🎜#이 코드 조각은 PDFKit 문서에서 가져온 것입니다. 그러나 기존(계속 변경되는) HTML 페이지를 변환하는 대신 PDF 파일을 직접 생성하는 것이 목표라면 여전히 유용할 수 있습니다. #🎜🎜##🎜🎜#최종 솔루션 3: Node.js 기반 Puppeteer 및 헤드리스 Chrome#🎜🎜##🎜🎜#Puppeteer란 무엇인가요? 문서 내용은 다음과 같습니다. #🎜🎜##🎜🎜#
Puppeteer는 DevTools 프로토콜에서 Chrome 또는 Chromium을 제어하기 위한 고급 API를 제공하는 노드 라이브러리입니다. Puppeteer는 기본적으로 헤드리스 모드에서 Chrome 또는 Chromium을 실행하지만 전체(비헤드리스) 모드에서 실행되도록 구성할 수도 있습니다.
#🎜🎜#기본적으로 Node.js에서 실행할 수 있는 브라우저입니다. 문서를 읽으면 가장 먼저 언급되는 것은 Puppeteer를 사용하여 #🎜🎜#스크린샷과 PDF#🎜🎜# 페이지를 생성할 수 있다는 것입니다. 훌륭한! 이것이 바로 우리가 원하는 것입니다. #🎜🎜##🎜🎜#먼저 npmi i puppeteer를 사용하여 Puppeteer를 설치하고 기능을 구현하세요. #🎜🎜#
printPDF.then(pdf => {
    res.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length })
    res.send(pdf)
#🎜🎜#이것은 URL로 이동하여 사이트의 PDF 파일을 생성하는 간단한 기능입니다. #🎜🎜##🎜🎜#먼저 브라우저를 시작한 다음(PDF 생성은 헤드리스 모드에서만 지원됨) 새 페이지를 열고 뷰포트를 설정한 후 제공된 URL로 이동합니다. #🎜🎜##🎜🎜# waitUntil:'networkidle0' 옵션을 설정하면 Puppeteer는 최소 500밀리초 동안 네트워크 연결이 없으면 탐색이 완료된 것으로 간주합니다. (자세한 내용은 API 문서에서 확인할 수 있습니다.) #🎜🎜##🎜🎜##🎜🎜#이후 PDF를 변수로 저장하고 브라우저를 닫은 후 PDF로 돌아갑니다. #🎜🎜##🎜🎜##🎜🎜#참고: page.pdf 메서드는 options 개체를 수신하며 'path' 옵션을 사용하여 파일을 저장할 수 있습니다. 디스크에. 경로가 제공되지 않으면 PDF가 디스크에 저장되지 않고 대신 버퍼링됩니다. (나중에 어떻게 처리할지 논의하겠습니다.) #🎜🎜##🎜🎜# 보호된 페이지에서 PDF를 생성하기 전에 로그인해야 하는 경우 먼저 로그인 페이지로 이동하여 다음을 확인하세요. 양식 요소의 ID 또는 이름을 입력하고 양식을 제출합니다. #🎜🎜#
function getPDF() {
 return axios.get(`${API_URL}/your-pdf-endpoint`, {
   responseType: 'arraybuffer',
   headers: {
     'Accept': 'application/pdf'
   }
 })
#🎜🎜#로그인 자격 증명을 항상 환경 변수에 저장하고 하드코딩하지 마세요! #🎜🎜#

样式控制

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>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 p {
        break-after: always;
    }
}

上面的 CSS 隐藏了打印按钮,并在每个 p 之后插入一个分页符,其中包含content 类。有一篇很棒的文章总结了你可以用打印规则做什么,以及它们有什么问题,包括浏览器兼容性。

考虑到所有因素,如果你想从不那么复杂的页面生成 PDF,CSS打印规则非常有效。

总结

让我们快速回顾前面介绍的方案,以便从 HTML 页面生成 PDF 文件:

从 DOM 产生截图:当你需要从页面创建快照时(例如创建缩略图)可能很有用,但是当你需要处理大量数据时就会有些捉襟见肘。

只用 PDF 库:如果你打算从头开始以编程方式创建 PDF 文件,这是一个完美的解决方案。否则,你需要同时维护 HTML 和 PDF 模板,这绝对是一个禁忌。

Puppeteer:尽管在 Docker 上工作相对困难,但它为我们的实现提供了最好的结果,而且编写代码也是最简单的。

CSS打印规则:如果你的用户受过足够的教育,知道如何把页面内容打印到文件,并且你的页面相对简单,那么它可能是最轻松的解决方案。正如你在我们的案例中所看到的,事实并非如此。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的HTML视频教程栏目!

위 내용은 HTML을 PDF로 변환하는 4가지 방법 소개(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 segmentfault에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
HTML의 부울 속성은 무엇입니까? 몇 가지 예를 들어주십시오.HTML의 부울 속성은 무엇입니까? 몇 가지 예를 들어주십시오.Apr 25, 2025 am 12:01 AM

부울 속성은 값없이 활성화되는 HTML의 특수 속성입니다. 1. 부울 속성은 입력 상자를 비활성화하는 등의 존재 여부에 따라 요소의 동작을 제어합니다. 2. 작업 원칙은 브라우저가 구문 분석 할 때 속성의 존재에 따라 요소 동작을 변경하는 것입니다. 3. 기본 사용법은 속성을 직접 추가하는 것이며, 고급 사용량은 JavaScript를 통해 동적으로 제어 될 수 있습니다. 4. 일반적인 실수는 값을 설정해야한다고 잘못 생각하고 올바른 글쓰기 방법은 간결해야합니다. 5. 모범 사례는 코드를 간결하게 유지하고 부울 속성을 합리적으로 사용하여 웹 페이지 성능 및 사용자 경험을 최적화하는 것입니다.

HTML 코드를 어떻게 검증 할 수 있습니까?HTML 코드를 어떻게 검증 할 수 있습니까?Apr 24, 2025 am 12:04 AM

HTML 코드는 온라인 유효성 검사기, 통합 도구 및 자동화 된 프로세스를 통해 깨끗할 수 있습니다. 1) w3cmarkupvalidationservice를 사용하여 온라인으로 HTML 코드를 확인하십시오. 2) 실시간 확인을 위해 VisualStudioCode에 HTMLHINT 확장을 설치하고 구성하십시오. 3) htmltidy를 사용하여 시공 프로세스에서 HTML 파일을 자동으로 확인하고 청소하십시오.

HTML vs. CSS 및 JavaScript : 웹 기술 비교HTML vs. CSS 및 JavaScript : 웹 기술 비교Apr 23, 2025 am 12:05 AM

HTML, CSS 및 JavaScript는 최신 웹 페이지를 구축하기위한 핵심 기술입니다. 1. HTML 웹 페이지 구조를 정의합니다. 2. CSS는 웹 페이지의 모양을 담당합니다.

마크 업 언어로서의 HTML : 기능과 목적마크 업 언어로서의 HTML : 기능과 목적Apr 22, 2025 am 12:02 AM

HTML의 기능은 웹 페이지의 구조와 내용을 정의하는 것이며, 그 목적은 정보를 표시하는 표준화 된 방법을 제공하는 것입니다. 1) HTML은 타이틀 및 단락과 같은 태그 및 속성을 통해 웹 페이지의 다양한 부분을 구성합니다. 2) 콘텐츠 및 성능 분리를 지원하고 유지 보수 효율성을 향상시킵니다. 3) HTML은 확장 가능하므로 사용자 정의 태그가 SEO를 향상시킬 수 있습니다.

HTML, CSS 및 JavaScript의 미래 : 웹 개발 동향HTML, CSS 및 JavaScript의 미래 : 웹 개발 동향Apr 19, 2025 am 12:02 AM

HTML의 미래 트렌드는 의미론 및 웹 구성 요소이며 CSS의 미래 트렌드는 CSS-In-JS 및 CSShoudini이며, JavaScript의 미래 트렌드는 WebAssembly 및 서버리스입니다. 1. HTML 시맨틱은 접근성과 SEO 효과를 향상시키고 웹 구성 요소는 개발 효율성을 향상 시키지만 브라우저 호환성에주의를 기울여야합니다. 2. CSS-in-JS는 스타일 관리 유연성을 향상 시키지만 파일 크기를 증가시킬 수 있습니다. CSShoudini는 CSS 렌더링의 직접 작동을 허용합니다. 3. Webosembly는 브라우저 애플리케이션 성능을 최적화하지만 가파른 학습 곡선을 가지고 있으며 서버리스는 개발을 단순화하지만 콜드 스타트 ​​문제의 최적화가 필요합니다.

HTML : 구조, CSS : 스타일, 자바 스크립트 : 동작HTML : 구조, CSS : 스타일, 자바 스크립트 : 동작Apr 18, 2025 am 12:09 AM

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. 1. HTML은 웹 페이지 구조를 정의하고, 2. CSS는 웹 페이지 스타일을 제어하고 3. JavaScript는 동적 동작을 추가합니다. 그들은 함께 현대 웹 사이트의 프레임 워크, 미학 및 상호 작용을 구축합니다.

HTML의 미래 : 웹 디자인의 진화 및 트렌드HTML의 미래 : 웹 디자인의 진화 및 트렌드Apr 17, 2025 am 12:12 AM

HTML의 미래는 무한한 가능성으로 가득합니다. 1) 새로운 기능과 표준에는 더 많은 의미 론적 태그와 WebComponents의 인기가 포함됩니다. 2) 웹 디자인 트렌드는 반응적이고 접근 가능한 디자인을 향해 계속 발전 할 것입니다. 3) 성능 최적화는 반응 형 이미지 로딩 및 게으른로드 기술을 통해 사용자 경험을 향상시킬 것입니다.

HTML vs. CSS vs. JavaScript : 비교 개요HTML vs. CSS vs. JavaScript : 비교 개요Apr 16, 2025 am 12:04 AM

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. HTML은 컨텐츠 구조를 담당하고 CSS는 스타일을 담당하며 JavaScript는 동적 동작을 담당합니다. 1. HTML은 태그를 통해 웹 페이지 구조와 컨텐츠를 정의하여 의미를 보장합니다. 2. CSS는 선택기와 속성을 통해 웹 페이지 스타일을 제어하여 아름답고 읽기 쉽게 만듭니다. 3. JavaScript는 스크립트를 통해 웹 페이지 동작을 제어하여 동적 및 대화식 기능을 달성합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음