개발천재

[ReactJS] PDF 다운로드 기능 구현하기, jsPDF + html2canvas 본문

개발 준비/ReactJS

[ReactJS] PDF 다운로드 기능 구현하기, jsPDF + html2canvas

세리블리 2025. 5. 13. 13:44
728x90
반응형

React에서 PDF 다운로드 기능을 구현하는 방법은 여러 가지가 있지만, 사용자 브라우저에서 PDF 파일을 생성하고 다운로드 하도록 하는 방법이 가장 일반적이다. 가장 많이 쓰는 라이브러리는 jspdf, tml2canvas이다. 이 외에도 react-pdf와 pdfmake도 있다.

 

 

 


 

 

jsPDF + html2canvas

jsPDF는 자바스크립트로 클라이언트 측에서 PDF 파일을 생성할 수 있게 해주는 라이브러리이다. 기본적으로 텍스트, 이미지, 테이블, 도형 등을 코드로 직접 그리는 방식이며, save() 함수를 통해 사용자가 PDF 파일을 다운로드할 수 있도록 제공한다. 그러나 기본 내장 폰트는 영문 위주이기 때문에 한글을 출력하려면 별도의 폰트 파일을 등록해줘야 한다. 간단한 영문 PDF 문서나 테이블 기반 출력에는 매우 가볍고 효과적인 도구이다.

 

html2canvas는 HTML 요소를 브라우저 화면에서 그대로 캡처하여 Canvas 이미지로 변환해주는 라이브러리이다. 이 라이브러리를 활용하면 사용자가 보고 있는 HTML 레이아웃을 그대로 이미지화할 수 있어, jsPDF와 함께 사용하면 PDF에 HTML의 시각적 결과물을 그대로 삽입할 수 있다. 다만, 텍스트가 벡터 형태가 아니라 이미지로 처리되므로 검색 불가 및 용량 증가 등의 한계가 있다. 주로 화면 출력물(예: 영수증, 견적서 등)을 그대로 저장할 때 유용하다.

 

화면을 그대로 pdf로 저장하고 싶거나, 시각적 레이아웃이 중요한 문서이거나, 캡처 기반의 빠른 구현을 원할 때 이 두가지를 함께 사용한다.

 

 

jsPDF + html2canvas 사용방법

라이브러리 설치하기
아래의 명령어를 터미널에 입력하여 jspdf, html2canvas를 설치한다.

npm install jspdf html2canvas



PDF 다운로드 버튼 만들기

// DownloadPDFButton.tsx
import React from "react";
import jsPDF from "jspdf";
import html2canvas from "html2canvas";

const DownloadPDFButton = () => {
  const handleDownload = async () => {
    const element = document.getElementById("pdf-content");
    if (!element) return;

    const canvas = await html2canvas(element);
    const imgData = canvas.toDataURL("image/png");

    const pdf = new jsPDF("p", "mm", "a4");

    const imgProps = pdf.getImageProperties(imgData);
    const pdfWidth = pdf.internal.pageSize.getWidth();
    const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;

    pdf.addImage(imgData, "PNG", 0, 0, pdfWidth, pdfHeight);
    pdf.save("download.pdf");
  };

  return <button onClick={handleDownload}>PDF 다운로드</button>;
};

export default DownloadPDFButton;



PDF로 저장할 영역 만들기

// App.tsx
import React from "react";
import DownloadPDFButton from "./DownloadPDFButton";

const App = () => {
  return (
    <div>
      <div id="pdf-content" style={{ padding: "20px", background: "#f4f4f4" }}>
        <h1>견적서</h1>
        <p>고객명: 홍길동</p>
        <p>서비스: 이사 서비스</p>
        <p>가격: 500,000원</p>
      </div>
      <DownloadPDFButton />
    </div>
  );
};

export default App;



pdf로 추출할 영역을 한페이지로 담지 못할 때는 여러 페이지에 나눠 넣을 수 있도록 pdf.addPage()를 사용한다.

import React from "react";
import jsPDF from "jspdf";
import html2canvas from "html2canvas";

const DownloadMultiPagePDF = () => {
  const handleDownload = async () => {
    const element = document.getElementById("pdf-content");
    if (!element) return;

    const canvas = await html2canvas(element);
    const imgData = canvas.toDataURL("image/png");

    const pdf = new jsPDF("p", "mm", "a4");
    const pdfWidth = pdf.internal.pageSize.getWidth();
    const pdfHeight = pdf.internal.pageSize.getHeight();

    const imgProps = pdf.getImageProperties(imgData);
    const imgWidth = pdfWidth;
    const imgHeight = (imgProps.height * imgWidth) / imgProps.width;

    let heightLeft = imgHeight;
    let position = 0;

    // 첫 페이지
    pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);
    heightLeft -= pdfHeight;

    // 추가 페이지가 필요하면 계속 addPage()
    while (heightLeft > 0) {
      position = heightLeft - imgHeight;
      pdf.addPage();
      pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);
      heightLeft -= pdfHeight;
    }

    pdf.save("multi-page.pdf");
  };

  return <button onClick={handleDownload}>여러 페이지 PDF 다운로드</button>;
};

export default DownloadMultiPagePDF;

 

 


 

 

react-pdf

react-pdf는 React 환경에서 PDF 문서를 컴포넌트 기반으로 작성하고 렌더링할 수 있게 해주는 라이브러리이다. HTML이나 CSS 대신, Text, View, Page, Document 같은 전용 컴포넌트를 사용하여 PDF 레이아웃을 정의하며, JSX 문법을 활용해 마치 일반 React 페이지처럼 문서를 구성할 수 있다. 커스텀 폰트 등록, 스타일링, 이미지 삽입 등도 가능하며, 특히 서버 사이드 렌더링(SSR)이나 React 기반 웹앱에서 동적으로 생성된 PDF 문서를 제공하고자 할 때 유용하다.

 

react-pdf 설치하기

아래의 명령어를 터미널에 입력하여 react-pdf를 설치한다.

npm install @react-pdf/renderer

 

react-pdf 사용예제

컴포넌트 생성

// components/MyPDFDocument.tsx
import React from "react";
import { Page, Text, View, Document, StyleSheet } from "@react-pdf/renderer";

const styles = StyleSheet.create({
  page: { padding: 30 },
  section: { marginBottom: 10 },
});

const MyPDFDocument = ({ customerName, service }) => (
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>견적서</Text>
      </View>
      <View style={styles.section}>
        <Text>고객명: {customerName}</Text>
        <Text>서비스: {service}</Text>
      </View>
    </Page>
  </Document>
);

export default MyPDFDocument;

 

 

다운로드 버튼 만들기

// 다운로드 버튼
import React from "react";
import { PDFDownloadLink } from "@react-pdf/renderer";
import MyPDFDocument from "./MyPDFDocument";

const DownloadPDF = () => (
  <PDFDownloadLink
    document={<MyPDFDocument customerName="홍길동" service="이사" />}
    fileName="estimate.pdf"
  >
    {({ loading }) => (loading ? "로딩 중..." : "PDF 다운로드")}
  </PDFDownloadLink>
);

export default DownloadPDF;

 

 


 

 

pdfmake

pdfmake는 JSON 구조로 PDF를 생성한다. 텍스트, 테이블, 스타일 지정이 간편하다는 장점이 있고, 서버에서도 사용이 가능하다. 복잡한 문서 레이아웃에 주로 사용한다. (테이블, 다중 열 등)

 

pdfmake 설치하기

아래의 명령어를 터미널에 입력하여 pdfmake를 설치한다.

npm install pdfmake

 

 

사용예제

import React from "react";
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";

// 폰트 등록
pdfMake.vfs = pdfFonts.pdfMake.vfs;

const DownloadWithPdfMake = () => {
  const generatePDF = () => {
    const docDefinition = {
      content: [
        { text: "견적서", style: "header" },
        { text: "고객명: 홍길동" },
        { text: "서비스: 이사 서비스" },
        {
          table: {
            body: [
              ["항목", "수량", "가격"],
              ["박스포장", "10", "100,000"],
              ["운반비", "1", "400,000"],
            ],
          },
        },
      ],
      styles: {
        header: {
          fontSize: 18,
          bold: true,
        },
      },
    };

    pdfMake.createPdf(docDefinition).download("estimate.pdf");
  };

  return <button onClick={generatePDF}>pdfmake로 PDF 다운로드</button>;
};

export default DownloadWithPdfMake;
반응형