찾다
웹 프론트엔드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, CSS 및 JavaScript 이해 : 초보자 안내서HTML, CSS 및 JavaScript 이해 : 초보자 안내서Apr 12, 2025 am 12:02 AM

WebDevelopmentReliesonHtml, CSS 및 JavaScript : 1) HtmlStructuresContent, 2) CSSSTYLESIT, 및 3) JAVASCRIPTADDSINGINTERACTIVITY, BASISOFMODERNWEBEXPERIENCES를 형성합니다.

HTML의 역할 : 웹 컨텐츠 구조HTML의 역할 : 웹 컨텐츠 구조Apr 11, 2025 am 12:12 AM

HTML의 역할은 태그 및 속성을 통해 웹 페이지의 구조와 내용을 정의하는 것입니다. 1. HTML은 읽기 쉽고 이해하기 쉽게하는 태그를 통해 컨텐츠를 구성합니다. 2. 접근성 및 SEO와 같은 시맨틱 태그 등을 사용하십시오. 3. HTML 코드를 최적화하면 웹 페이지로드 속도 및 사용자 경험이 향상 될 수 있습니다.

HTML 및 코드 : 용어를 자세히 살펴 봅니다HTML 및 코드 : 용어를 자세히 살펴 봅니다Apr 10, 2025 am 09:28 AM

"Code"는 "Code"BroadlyIncludeLugageslikeJavaScriptandPyThonforFunctureS (htMlisAspecificTypeofCodeFocudecturecturingWebContent)

HTML, CSS 및 JavaScript : 웹 개발자를위한 필수 도구HTML, CSS 및 JavaScript : 웹 개발자를위한 필수 도구Apr 09, 2025 am 12:12 AM

HTML, CSS 및 JavaScript는 웹 개발의 세 가지 기둥입니다. 1. HTML은 웹 페이지 구조를 정의하고 등과 같은 태그를 사용합니다. 2. CSS는 색상, 글꼴 크기 등과 같은 선택기 및 속성을 사용하여 웹 페이지 스타일을 제어합니다.

HTML, CSS 및 JavaScript의 역할 : 핵심 책임HTML, CSS 및 JavaScript의 역할 : 핵심 책임Apr 08, 2025 pm 07:05 PM

HTML은 웹 구조를 정의하고 CSS는 스타일과 레이아웃을 담당하며 JavaScript는 동적 상호 작용을 제공합니다. 세 사람은 웹 개발에서 의무를 수행하고 화려한 웹 사이트를 공동으로 구축합니다.

HTML은 초보자를 위해 쉽게 배우나요?HTML은 초보자를 위해 쉽게 배우나요?Apr 07, 2025 am 12:11 AM

HTML은 간단하고 배우기 쉽고 결과를 빠르게 볼 수 있기 때문에 초보자에게 적합합니다. 1) HTML의 학습 곡선은 매끄럽고 시작하기 쉽습니다. 2) 기본 태그를 마스터하여 웹 페이지를 만들기 시작하십시오. 3) 유연성이 높고 CSS 및 JavaScript와 함께 사용할 수 있습니다. 4) 풍부한 학습 리소스와 현대 도구는 학습 과정을 지원합니다.

HTML의 시작 태그의 예는 무엇입니까?HTML의 시작 태그의 예는 무엇입니까?Apr 06, 2025 am 12:04 AM

anexampleStartingtaginhtmlis, whithbeginsaparagraph.startingtagsareessentialinhtmlastheyinitiate rements, definetheirtypes, andarecrucialforstructurituringwebpages 및 smanstlingthedom.

메뉴에서 점선 분할 효과의 중심 정렬을 달성하기 위해 CSS의 Flexbox 레이아웃을 사용하는 방법은 무엇입니까?메뉴에서 점선 분할 효과의 중심 정렬을 달성하기 위해 CSS의 Flexbox 레이아웃을 사용하는 방법은 무엇입니까?Apr 05, 2025 pm 01:24 PM

메뉴에서 점선 분할 효과를 설계하는 방법은 무엇입니까? 메뉴를 설계 할 때는 일반적으로 접시 이름과 가격 사이에 왼쪽과 오른쪽을 정렬하는 것이 어렵지 않지만 점선 또는 중간의 점은 어떻습니까?

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 옷 제거제

AI Hentai Generator

AI Hentai Generator

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

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

mPDF

mPDF

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

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

SecList

SecList

SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

MinGW - Windows용 미니멀리스트 GNU

MinGW - Windows용 미니멀리스트 GNU

이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.