개발

자바스크립트로 PDF 내보내기

동고킴 2022. 9. 16. 10:38
반응형

 

자바스크립트로 PDF 생성 및 화면 내보내기

 

자바스크립트 화면 캡처에 이어 PDF 내보내기이다. PDF 생성은 jsPDF 라이브러리를 사용할 것이다. 간단한 텍스트, 표 생성 및 한글 깨짐 현상 해결 및 화면(dom 영역)을 캡처하여 PDF로 저장해보자

 

1. 기본 옵션 확인 및 PDF 생성. 한글 깨짐 현상 해결

jsPDF 설치

npm install jspdf --save
# or
yarn add jspdf

 

간단한 jsPDF 설정 및 문자열 출력

import { jsPDF } from "jspdf";

const doc = new jsPDF({
	orientation: "p", // p: 가로(기본), l: 세로
    unit: "mm", // 단위 : "pt" (points), "mm", "cm", "m", "in" or "px" 등)
    format: "a4", // 포맷 (페이지 크기).
});
doc.text("Hello world! page1", 10, 10); // 텍스트, x, y
doc.addPage(); // 페이지 추가
doc.text("Hello world! page2", 10, 10);
doc.addPage();
doc.text("Hello world! page3", 10, 10);
doc.setPage(1); // 페이지 이동
doc.text("Hello world! page1-2", 10, 20);

doc.save("first_PDF.pdf"); // PDF 저장

 

아래처럼 PDF가 생성된다. 하지만 한글이 깨진다.

 

 

PDF 있는 14개의 표준 글꼴은 ASCII 코드 페이지로 제한된다. UTF-8 사용하려면 필요한 폰트를 사용하면 된다. jsPDF는 .ttf 파일을 지원하고있다. base64 인코딩 형태로 변환한 폰트를 세팅해주면 된다.

인코딩은 jsPDF에서 지원하는 폰트 컨버터를 이용해서 js 파일을 생성한 후 꺼내서도 되지만 개인적으로는 아래 사이트에서 인코딩하는 게 더 편한 것 같다.

https://www.giftofspeed.com/base64-encoder/

 

맑은고딕 폰트를 사용한 예시다. 예시처럼 인코딩 된 폰트를 직접 선언하지 말고 파일을 별도로 분리해서 사용하는 걸 추천한다. 인코딩은 폰트 설정이 된 후부터 적용된다는 점에 유의하자

import { jsPDF } from "jspdf";

const doc = new jsPDF({
  orientation: "p", // p: 가로(기본), l: 세로
  unit: "mm", // 단위 : "pt" (points), "mm", "in" or "px" 등)
  format: "a4", // 포맷 (페이지 크기).
});

doc.text("Hello world! page1", 10, 10); // 텍스트, x, y
doc.addPage(); // 페이지 추가
doc.text("Hello world! page2", 10, 10);
doc.addPage();
doc.text("Hello world! page3", 10, 10);
doc.setPage(1); // 페이지 이동
doc.text("Hello world! page1-2", 10, 20);

doc.save("first_PDF.pdf"); // PDF 저장

const font = "AAEAAAAWAQAABABgRFNJRySiJ..."; // 생략
doc.addFileToVFS("malgun.ttf", font);
doc.addFont("malgun.ttf", "malgun", "normal");
doc.setFont("malgun");

doc.text("안녕하세요 ^^", 10, 30);

doc.save("first_PDF.pdf"); // PDF 저장

 

2. 표 만들기 (jspdf-autotable)

PDF에 표를 생성해보자. jspdf와  jspdf-autotable 라이브러리를 함께 사용한다.

 

jspdf-autotable 설치

npm install jspdf-autotable --save

 

html table을 가져와서 만들 경우

<table id="my-table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Country</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>David</td>
      <td>david@example.com</td>
      <td>Sweden</td>
    </tr>
    <tr>
      <td>Castille</td>
      <td>castille@example.com</td>
      <td>Spain</td>
    </tr>
  </tbody>
</table>
import { jsPDF } from "jspdf";
import autoTable from "jspdf-autotable";

const doc = new jsPDF({
  orientation: "p",
  unit: "mm",
  format: "a4",
});

// 1) html 파싱해서 생성
autoTable(doc, { html: "#my-table" });

// 2) javascript로 직접 표 생성
autoTable(doc, {
  head: [["Name", "Email", "Country"]],
  body: [
    ["David", "david@example.com", "Sweden"],
    ["Castille", "castille@example.com", "Spain"],
    // ...
  ],
});

doc.save("table.pdf");

 

서버에서 데이터를 받아와서 출력하는 경우에는 아래처럼 설정하는 것이 더 편하다. 스타일도 함께 설정한 예이다.

autoTable(doc, {
  headStyles: { halign: "center" }, // head 스타일
  columnStyles: { name: { halign: "center" } }, // cloumn 스타일
  columns: [
    { header: "Name", dataKey: "name" },
    { header: "Email", dataKey: "email" },
    { header: "Country", dataKey: "country" },
  ],
  body: [
    { name: "David", email: "david@example.com", country: "Sweden" },
    {
      name: "Castille",
      email: "castille@example.com",
      country: "Spain",
    },
  ],
});

 

 

3. 화면 PDF로 내보내기 (html2canvas)

위는 직접 PDF 내용을 만들었다면 이번에는 화면을 그대로 PDF로 내보내기 하는 방법이다. html2canvas 라이브러리를 사용하여 화면을 canvas로 변환한 후 PDF로 내보낼 수 있다. html2canvas 사용방법은 이전 포스트인 '자바스크립트 화면 캡쳐를 해보자'를 참고하면 되고, html2canvas의 동작 방식이 궁금하다면 'html2canvas는 어떻게 캔버스를 그릴까' 포스트를 참고바란다.

 

설치

npm install --save html2canvas

htm2canvas로 화면을 캔버스로 변환한 후, 캔버스를 다시 이미지로 변환하여 PDF로 내보낸다.

import html2canvas from "html2canvas";

html2canvas(document.body).then((canvas) => {
  // 캔버스를 이미지로 변환
  const imgData = canvas.toDataURL("image/png");

  const imgWidth = 210; // 가로(mm) (A4)
  const pageHeight = imgWidth * 1.414; // 세로 길이 (A4)
  const imgHeight = (canvas.height * imgWidth) / canvas.width;

  const doc = new jsPDF({
    orientation: "p",
    unit: "mm",
    format: "a4",
  });

  let heightLeft = imgHeight;
  let position = 0;

  // 첫 페이지 출력
  doc.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);
  heightLeft -= pageHeight;

  // 한 페이지 이상일 경우 루프 돌면서 출력
  while (heightLeft >= 20) {
    position = heightLeft - imgHeight;
    doc.addPage();
    doc.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);
    heightLeft -= pageHeight;
  }

  doc.save("capture.pdf");
});

 

 

반응형