如何使用 JavaScript 產生與編輯 PDF 檔案:完整指南、函式庫與實作範例

目次

1. 介紹:為什麼我們需要在 JavaScript 中處理 PDF?

PDF 處理的重要性與 JavaScript 的角色

近年來,PDF 已成為商業與個人使用中不可或缺的檔案格式。合約、收據、發票與報告等文件,現在大多以 PDF 形式產生。因此,各種開發環境對於自動化產生與編輯 PDF 檔案的需求日益提升。
JavaScript 直接在瀏覽器中執行,擅長動態的客戶端操作。善用這些能力即可高效地產生與編輯 PDF 檔案。特別是能在純客戶端完成 PDF 處理——不必依賴伺服器——的做法,近年受到廣泛關注。

使用 JavaScript 處理 PDF 的好處

1. 減輕伺服器負擔

過去 PDF 的產生與編輯多在伺服器端完成。改以 JavaScript 在客戶端處理,可大幅降低伺服器的工作量。

2. 即時處理

透過 JavaScript,使用者的輸入可以立即反映在 PDF 中。例如,表單資料可即時轉換為 PDF,並提供下載連結。

3. 高彈性與客製化

利用 JavaScript 函式庫,您可以輕鬆製作具圖形、圖片或格式化文字的高度客製化 PDF。因為 JavaScript 可在大多數現代瀏覽器上運行,環境特定的問題也會相對減少。

實務應用案例

1. 產生商業文件

可自動產生發票與收據,並直接以電子郵件寄出。亦能即時輸出針對每位客戶客製化的文件,提高工作效率。

2. 輸出表單資料

可實作將問卷或申請表資料儲存為 PDF,並匯入管理系統的功能。這有助於從紙本文件處理轉向數位化工作流程。

3. 建立報告與簡報素材

根據資料動態產生報告,並可加入圖表與圖片。大幅縮短會議或簡報素材的製作時間。

未來趨勢與展望

基於 JavaScript 的 PDF 處理預計會持續演進,以下兩大趨勢受到矚目:

  1. 更強的雲端整合:與雲端儲存或資料庫的無縫結合,將提升具備內建 PDF 產生與編輯功能的 Web 應用需求。
  2. 行動支援的提升:隨著智慧手機與平板電腦的使用率提升,針對響應式版面的 PDF 產生將持續進步。

2. 前五大 JavaScript PDF 函式庫(含比較表)

為何要挑選合適的 JavaScript PDF 函式庫

在使用 JavaScript 產生或編輯 PDF 時,選對函式庫至關重要。合適的函式庫能提升開發效率,並提供進階的客製化功能(例如日文文字支援)。本節將介紹五大主流 PDF 函式庫,並比較其特性與適用情境。

1. PDF.js

概觀

PDF.js 是由 Mozilla 開發的開源 PDF 檢視函式庫,專注於在瀏覽器內渲染 PDF。

功能

  • 僅檢視器:僅負責顯示,不支援 PDF 產生或編輯。
  • 高相容性:僅使用 HTML5 與 JavaScript,無需外掛。
  • 高效能:渲染速度快,能有效處理大型文件。

使用情境

  • 需要 PDF 檢視的應用,例如電子書或合約檢視。

2. jsPDF

概觀

jsPDF 是一套輕量級函式庫,主要用於產生 PDF 檔案。它允許輕鬆插入文字、圖片與表格,適合簡易文件的建立。

功能

  • PDF 產生:適合在客戶端建立 PDF。
  • 可擴充:支援外掛以加入額外功能。
  • 日文支援:透過字型設定即可支援日文。

使用情境

  • 自動產生收據、發票或簡易報告。

3. pdf-lib

概觀

pdf-lib 不僅支援 PDF 產生,還支援編輯與合併。它相容於 TypeScript,且能順利整合至現代開發環境。

功能

  • 編輯功能: 在現有 PDF 中加入文字或影像。
  • 彈性客製化: 提供字型嵌入與版面控制。
  • 高效能: 即使在大規模 PDF 操作上亦能保持效能。

使用情境

  • 建立 PDF 表單或動態資料報告。

4. pdfmake

概觀

pdfmake 允許使用宣告式 API 輕鬆指定版面配置,非常適合複雜設計與表格版面。

功能

  • 強大的版面能力: 輕鬆設定表格與樣式。
  • 多語言支援: 支援基本的日文字型。
  • 基於 JSON: 輕鬆建立動態文件。

使用情境

  • 報告、目錄與含有表格的文件。

5. html2pdf

概觀

html2pdf 可直接將 HTML 元素轉換為 PDF 檔案,適合根據現有網頁設計產生 PDF。

功能

  • 基於 HTML: 在 PDF 輸出中保留 HTML/CSS 設計。
  • 易於使用: 快速設定即可產生簡易輸出。
  • 響應式友好: 在行動裝置上保持版面。

使用情境

  • 為網頁提供列印功能或產生固定版面的 PDF 輸出。

6. 比較表

LibraryViewerGenerateEditJapanese SupportKey Features
PDF.js××Focused on PDF viewing, fast rendering
jsPDF×Simple PDF creation, plugin extensibility
pdf-lib×Full-featured editing, TypeScript support
pdfmake×Powerful layout with declarative API
html2pdf××HTML-based easy PDF output

總結

每個 JavaScript PDF 函式庫都有不同的優勢:

  • PDF.js: 最適合僅供檢視。
  • jsPDF: 最適合簡易 PDF 產生。
  • pdf-lib: 適合編輯或加入複雜功能。
  • pdfmake: 在表格與自訂版面設計上表現強大。
  • html2pdf: 想保留 HTML 設計時的最佳選擇。

3. 實作範例:使用 JavaScript 產生與編輯 PDF

介紹

JavaScript 讓客戶端 PDF 產生與編輯變得簡單。本節將介紹使用主要函式庫的具體實作,請嘗試執行這些程式碼範例以了解其運作方式。

1. 使用 jsPDF 產生基本 PDF

建立簡易文字 PDF

const doc = new jsPDF();
doc.text("Hello, PDF!", 10, 10);
doc.save("sample.pdf");

重點說明

  1. 建立實例:
  • new jsPDF() 會建立一個新的 PDF 文件。
  1. 加入文字:
  • doc.text() 會在座標 (10, 10) 放置「Hello, PDF!」。
  1. 儲存 PDF:
  • doc.save() 會下載名為「sample.pdf」的 PDF。

範例:加入影像

const doc = new jsPDF();
const imgData = 'data:image/jpeg;base64,...';
doc.addImage(imgData, 'JPEG', 10, 40, 180, 160);
doc.save("image-sample.pdf");

2. 使用 pdf-lib 編輯 PDF

在現有 PDF 中加入文字

import { PDFDocument } from 'pdf-lib';

async function modifyPDF() {
  const url = 'sample.pdf';
  const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer());
  const pdfDoc = await PDFDocument.load(existingPdfBytes);
  const pages = pdfDoc.getPages();
  const firstPage = pages[0];

  firstPage.drawText('追加されたテキスト', { x: 50, y: 500, size: 20 });

  const pdfBytes = await pdfDoc.save();
  download(pdfBytes, "modified-sample.pdf", "application/pdf");
}

重點說明

  1. 載入 PDF:
  • 使用 PDFDocument.load()
  1. 編輯 PDF:
  • drawText() 會在指定位置加入文字。
  1. 儲存與下載:
  • 儲存編輯後的 PDF 並下載。

3. 使用 pdfmake 建立版面密集的 PDF

建立複雜版面

const docDefinition = {
  content: [
    { text: 'レポートタイトル', style: 'header' },
    { text: '以下はサンプル表です。' },
    {
      table: {
        body: [
          ['項目1', '項目2', '項目3'],
          ['データ1', 'データ2', 'データ3'],
          ['データ4', 'データ5', 'データ6'],
        ],
      },
    },
  ],
  styles: {
    header: {
      fontSize: 18,
      bold: true,
      margin: [0, 0, 0, 10],
    },
  },
};
pdfMake.createPdf(docDefinition).download('sample-table.pdf');

重點說明

  1. 定義內容: 表格與文字皆在 content 中定義。
  2. 樣式定義: styles 控制字型與版面設定。
  3. 下載: 使用 download() 輸出 PDF。

4. Japanese Font Support (jsPDF)

const doc = new jsPDF();
doc.addFileToVFS('NotoSansJP-Regular.ttf', fontData);
doc.addFont('NotoSansJP-Regular.ttf', 'NotoSansJP', 'normal');
doc.setFont('NotoSansJP');
doc.text('日本語対応テスト', 10, 10);
doc.save("japanese-sample.pdf");

摘要

本節介紹了使用主要函式庫的實作範例:

  • jsPDF: 簡易的 PDF 建立與圖片插入。
  • pdf-lib: 編輯既有 PDF 與頁面操作。
  • pdfmake: 強大的表格與版面自訂,並支援部分日文。

4. 處理日文字型與除錯

前言

在 JavaScript 中產生 PDF 時,日文字型的處理是最常見的挑戰之一。常會出現字元無法辨識或缺字的問題。本節說明如何正確設定日文字型,並提供常見問題的除錯方法。

1. 日文字型的常見問題

為何必須嵌入字型

英文 PDF 通常使用預設字型即可正確顯示,但日文需要特別處理,原因如下:

  • 日文字型包含大量預設字型未提供的字元。
  • 部分函式庫的日文字型支援有限。
  • 若未嵌入字型,PDF 於不同環境下可能顯示錯誤。

常見錯誤

  • 字元亂碼: 以 □ 或 ? 顯示,因缺少字型支援。
  • 版面錯亂: 行距或字型大小不正確。
  • 字型載入失敗: 無法載入自訂字型檔。

2. jsPDF 的日文字型處理

準備字型檔案

要嵌入日文字型,需要 TrueType(.ttf)字型檔。範例:Noto Sans JP。

  1. 下載: 從 Google Fonts 取得 Noto Sans JP。
  2. 轉換為 Base64: 將字型檔轉成 Base64 字串。

範例程式碼

const doc = new jsPDF();
doc.addFileToVFS('NotoSansJP-Regular.ttf', fontData);
doc.addFont('NotoSansJP-Regular.ttf', 'NotoSansJP', 'normal');
doc.setFont('NotoSansJP');
doc.text('こんにちは、世界!', 10, 10);
doc.save('japanese-sample.pdf');

說明

  • addFileToVFS: 註冊 Base64 的字型資料。
  • addFont: 定義字型名稱與樣式。
  • setFont: 套用該字型。

3. pdfmake 的日文字型處理

準備與設定字型

var fonts = {
  Roboto: {
    normal: 'Roboto-Regular.ttf',
    bold: 'Roboto-Bold.ttf',
    italics: 'Roboto-Italic.ttf',
    bolditalics: 'Roboto-BoldItalic.ttf',
  },
};

var docDefinition = {
  content: [
    { text: '日本語テスト', font: 'Roboto', fontSize: 14 },
    { text: 'Hello, World!', fontSize: 12 },
  ],
};

pdfMake.createPdf(docDefinition).download('japanese-sample.pdf');

說明

  • 每種字型樣式必須分別設定。
  • 透過 font 屬性在 content 中指定使用的字型。

4. 除錯

文字顯示不正確

  • 可能原因: 字型檔或 Base64 轉換錯誤。
  • 解決方式: 1. 確認已正確嵌入 Base64。 2. 檢查 .ttf 檔案完整性。 3. 確認 MIME 類型正確。

版面錯亂

  • 原因: 行距設定不當。
  • 解決方式: 手動設定 fontSizelineHeight

行動裝置編碼問題

  • 原因: 裝置缺乏日文字型。
  • 解決方式: 必須始終嵌入字型。

摘要

  • jsPDF: 以 Base64 方式簡易嵌入字型。
  • pdfmake: 版面控制力強,但需詳細設定字型。

5. 進階技巧與使用案例解決方案

前言

JavaScript 的 PDF 函式庫可支援進階應用,如動態 PDF 產生、資料庫整合、客製化版面等。

1. 動態資料 PDF 產生

從 JSON 產生報表

const doc = new jsPDF();
const data = [
  { 名前: "山田太郎", 年齢: 30, 職業: "エンジニア" },
  { 名前: "佐藤花子", 年齢: 25, 職業: "デザイナー" },
  { 名前: "田中一郎", 年齢: 40, 職業: "マネージャー" },
];
doc.text('ユーザーレポート', 10, 10);
doc.autoTable({
  head: [['名前', '年齢', '職業']],
  body: data.map(item => [item.名前, item.年齢, item.職業]),
});
doc.save('report.pdf');

重點

  • 動態資料: 將 JSON 轉換為表格列。
  • 版面管理: 使用 autoTable 外掛輕鬆建立表格。

2. 合併與分割 PDF

合併多個 PDF(pdf‑lib)

import { PDFDocument } from 'pdf-lib';

async function mergePDFs(pdfUrls) {
  const mergedPdf = await PDFDocument.create();

  for (let url of pdfUrls) {
    const existingPdf = await fetch(url).then(res => res.arrayBuffer());
    const pdfDoc = await PDFDocument.load(existingPdf);
    const copiedPages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
    copiedPages.forEach(page => mergedPdf.addPage(page));
  }

  const pdfBytes = await mergedPdf.save();
  download(pdfBytes, "merged.pdf", "application/pdf");
}

重點

  • 從多個 PDF 複製頁面。
  • 合併為單一文件。

3. PDF 表單欄位

建立輸入欄位(pdf‑lib)

import { PDFDocument } from 'pdf-lib';

async function createForm() {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([500, 700]);

  const form = pdfDoc.getForm();
  const nameField = form.createTextField('name');
  nameField.setText('名前を入力してください');
  nameField.addToPage(page, { x: 50, y: 600, width: 300, height: 30 });

  const pdfBytes = await pdfDoc.save();
  download(pdfBytes, "form.pdf", "application/pdf");
}

重點

  • 支援動態使用者輸入。
  • 欄位資料可用於後續處理。

4. 自訂版面

頁首與頁腳(pdfmake)

const docDefinition = {
  header: { text: 'レポートヘッダー', alignment: 'center', margin: [0, 10, 0, 0] },
  footer: function(currentPage, pageCount) {
    return { text: `${currentPage} / ${pageCount}`, alignment: 'right', margin: [0, 0, 10, 0] };
  },
  content: [
    { text: 'レポート本文', fontSize: 12 },
  ],
};
pdfMake.createPdf(docDefinition).download('custom-layout.pdf');

5. 行動與響應式支援

從 HTML 產生 PDF(html2pdf)

const element = document.getElementById('content');
html2pdf(element);

總結

關鍵進階技巧:

  • 動態資料: 從 JSON 建立 PDF。
  • 合併/編輯: 使用 pdf‑lib 進行進階編輯。
  • 表單欄位: 建立互動式文件。
  • 自訂設計: 使用 pdfmake 製作版面豐富的文件。

6. 常見問題 (FAQ)

前言

本節回答開發者在使用 JavaScript 產生或編輯 PDF 時常見的問題。

1. 基本操作

Q1. 哪個函式庫最適合在 JavaScript 中產生 PDF?

A: 依需求選擇:

  • 簡易 PDF 產生: jsPDF
  • 編輯與合併: pdf‑lib
  • 複雜版面: pdfmake
  • HTML 轉 PDF: html2pdf

Q2. 如何正確顯示日文文字?

A: 請依以下步驟操作:

  1. 準備日文字型(Noto Sans JP、IPA 等)。
  2. 將字型轉為 Base64。
  3. 使用 addFileToVFS()addFont() 嵌入字型。
  4. 透過 setFont() 設定使用的字型。

Q3. 為何日文文字在行動裝置上會斷裂?

A: 行動裝置缺乏日文字型。
解決方案: 必須將日文字型嵌入 PDF。

Q4. 如何加入簽名欄位?

A: 可使用 pdf‑lib 插入簽名圖片:

page.drawImage(imgData, {
  x: 50,
  y: 100,
  width: 200,
  height: 100,
});

2. 進階使用

Q5. 能否在 PDF 中插入動態 QR Code?

A: 可以,使用 jsPDF。

Q6. 能否將 HTML 表單匯出為 PDF?

A: 可以,使用 html2pdf。

總結

本 FAQ 旨在協助您排除問題並優化 JavaScript PDF 工作流程。

7. 結論

前言

本文深入說明了如何使用 JavaScript 產生與編輯 PDF,涵蓋基礎操作、進階技巧、函式庫比較以及日文字型處理。

1. 基於 JavaScript 的 PDF 操作之便利性與彈性

JavaScript 在客戶端執行,能即時產生與編輯 PDF,降低伺服器負載,並支援互動功能。

好處:

  • 降低對伺服器的依賴
  • 即時互動與預覽
  • 與現代瀏覽器高度相容

2. 函式庫選擇彙總

LibraryFeaturesBest Use Cases
PDF.jsViewer onlyPDF display apps
jsPDFSimple & lightweightText and image PDFs
pdf-libEditing, merging, form creationComplex dynamic PDFs
pdfmakeAdvanced layoutReports, catalogs
html2pdfHTML/CSS to PDFWeb-page PDF output

3. 實作範例彙總

  • 基礎 PDF 建立
  • 動態資料報表
  • 編輯既有 PDF
  • 日文字型處理
  • 自訂設計與版面控制

4. 未來展望

JavaScript PDF 生態系統將持續演進:

  1. 雲端整合更完善
  2. AI 輔助文件產生
  3. 新函式庫提升速度與可擴展性

結論

JavaScript 正日益成為 Web 應用與企業系統中 PDF 處理的關鍵技術。透過運用本文討論的函式庫與技巧,您可以輕鬆實作彈性且高品質的 PDF 解決方案。

広告