2026/04/13

PDF生成 API vs ライブラリ徹底比較:どちらを選ぶべきか【2026年版】

PDF生成APIライブラリ比較

PDF生成はWebアプリケーション開発で避けて通れない要件です。請求書、レポート、契約書、証明書——あらゆるビジネスシーンでPDF出力が求められます。

このとき、大きく分けて2つのアプローチがあります。

  1. ライブラリ方式 — 自分のサーバーにPDF生成ライブラリを組み込む
  2. API方式 — クラウドのPDF生成APIにHTTPリクエストを送る

どちらにもメリット・デメリットがあり、プロジェクトの要件によって最適解は変わります。この記事では両方のアプローチを深く掘り下げ、判断基準を明確にします。

ライブラリ方式の概要

PDF生成ライブラリは長い歴史があり、多くの開発者にとって馴染みのある選択肢です。代表的なものを見てみましょう。

主要なPDF生成ライブラリ

ライブラリ 言語 方式
Puppeteer Node.js Headless Chromeを操作してHTML→PDF変換
wkhtmltopdf CLI QtWebKitベースの変換ツール(2023年アーカイブ)
pdfkit Node.js プログラムでPDFを直接構築
jsPDF JavaScript ブラウザ/Node.jsでPDF生成
TCPDF PHP PHPの定番PDF生成ライブラリ
ReportLab Python Python向けPDF生成(商用ライセンスあり)
Prawn Ruby Ruby向けPDF生成

ライブラリ方式のメリット

完全な制御が可能 ライブラリはすべて自分のインフラで動くため、レンダリングプロセスを完全にコントロールできます。カスタムフォントの配置、特殊な用紙サイズ、独自のヘッダー/フッター処理など、細かな調整が自在です。

外部依存がない ネットワーク越しの通信が発生しないため、オフライン環境でも動作します。外部サービスの障害に影響を受けることもありません。

ランニングコストが明確 API利用料が発生しないため、自社サーバーのコストだけで済みます。月間生成数が少ない場合はコスト面で有利です。

ライブラリ方式のデメリット

セットアップと保守が大変

Puppeteerを例にとると、Headless Chromeのインストール、フォントのプロビジョニング、メモリ管理、プロセスのクリーンアップなど、考慮すべき点が多数あります。

// Puppeteerでの請求書PDF生成
const puppeteer = require('puppeteer');

async function generateInvoice(html) {
  // Chromeプロセスの起動(メモリ消費大)
  const browser = await puppeteer.launch({
    headless: 'new',
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage', // Docker環境で必須
      '--font-render-hinting=none',
    ],
  });

  try {
    const page = await browser.newPage();
    await page.setContent(html, { waitUntil: 'networkidle0' });

    const pdf = await page.pdf({
      format: 'A4',
      margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
      printBackground: true,
    });

    return pdf;
  } finally {
    await browser.close(); // クリーンアップ必須
  }
}

日本語・CJKフォントの問題

Linux環境では日本語フォントが入っていないことが多く、「豆腐」(□□□)になるトラブルが頻発します。Dockerイメージにフォントをバンドルする必要があり、イメージサイズが肥大化します。

# Dockerfileでのフォント対応例
FROM node:20-slim

# 日本語フォントのインストール(+200MB以上)
RUN apt-get update && apt-get install -y \
    fonts-noto-cjk \
    fonts-noto-cjk-extra \
    && rm -rf /var/lib/apt/lists/*

スケーリングが難しい

Headless Chromeは1プロセスあたり100MB以上のメモリを消費します。同時10リクエストで1GB以上のメモリが必要になり、サーバーリソースの見積もりが複雑です。負荷に応じたオートスケーリングの仕組みも自前で構築する必要があります。

API方式の概要

PDF生成APIは、HTTPリクエストでHTMLやテンプレートを送信し、PDFバイナリを受け取るクラウドサービスです。インフラの管理を外部に委託することで、開発者はアプリケーションのロジックに集中できます。

API方式のメリット

セットアップがほぼ不要

APIキーを取得してHTTPリクエストを送るだけで、すぐにPDF生成を始められます。

# curlで即座にPDF生成(FUNBREW PDFの例)
curl -X POST https://pdf.funbrew.cloud/api/v1/generate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>請求書</h1><p>合計: ¥100,000</p>",
    "options": {
      "format": "A4",
      "margin": { "top": "20mm", "bottom": "20mm" }
    }
  }' \
  --output invoice.pdf

レンダリング品質が安定

API側でブラウザエンジン、フォント、レンダリング設定が最適化されており、環境による差異が発生しません。FUNBREW PDFのように日本語フォントを内蔵しているAPIなら、CJK問題も解消されます。

スケーリングが自動

月100件でも月100万件でも、同じAPIコールで対応できます。インフラのスケーリングはAPI側が行うため、開発者はサーバーリソースの心配をする必要がありません。

多言語対応

REST APIなので、どのプログラミング言語からでも呼び出せます。Node.js、Python、PHP、Ruby、Go——言語を問わず同じAPIを使えるのは、複数サービスを運用するチームにとって大きなメリットです。

API方式のデメリット

コストが発生する

API利用には料金がかかります。ただし、ライブラリ方式で必要なサーバーリソース・運用工数と比較すると、トータルコストでは逆転するケースも多いです。各APIの料金比較も参考にしてください。

ネットワーク依存

HTTPリクエストが必要なため、完全なオフライン環境では使えません。また、ネットワーク遅延が加算されます(ただし、レンダリング自体が高速なため、体感速度は十分実用的です)。

データプライバシーの考慮

HTMLコンテンツを外部サーバーに送信するため、極めて機密性の高いデータを扱う場合は社内ポリシーの確認が必要です。

比較表:API vs ライブラリ

項目 ライブラリ方式 API方式
初期セットアップ 数時間〜数日 数分
レンダリング品質 環境依存 安定
日本語/CJK対応 要フォント設定 内蔵済み(APIによる)
スケーリング 自前構築 自動
コストモデル サーバー費用 API利用料
保守負担 高い(OS・ライブラリ更新) 低い
オフライン動作 可能 不可
導入言語 ライブラリ依存 任意

判断フレームワーク:どちらを選ぶべきか

ライブラリ方式が適しているケース

  • シンプルなPDF:テキストと表だけの単純なレイアウト
  • CJK不要:英語のみのドキュメント
  • 低ボリューム:月に数十件程度の生成
  • データローカリティ必須:規制上、外部送信が不可能な環境
  • 既存資産がある:すでにPuppeteer等で安定稼働している仕組みがある

API方式が適しているケース

  • 複雑なレイアウト:CSSグリッド、Flexbox、背景画像を多用するデザイン
  • 日本語テキスト:CJKフォントの取り扱いが必要
  • 高ボリューム:月間数千〜数百万件の生成
  • 多言語チーム:Node.js、Python、PHPなど複数言語で同じPDF生成を行う
  • 素早い立ち上げ:MVPやプロトタイプで即座にPDF機能が欲しい

ライブラリからAPIへの移行パス

既存のPuppeteerベースのPDF生成をAPIに移行する場合、HTMLテンプレート部分はそのまま再利用できます。変更が必要なのは「HTMLをPDFに変換する」部分だけです。

// Before: Puppeteerで生成(30行以上のコード)
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({ /* 設定... */ });
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'networkidle0' });
const pdf = await page.pdf({ format: 'A4', printBackground: true });
await browser.close();

// After: APIで生成(5行)
const response = await fetch('https://pdf.funbrew.cloud/api/v1/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ html, options: { format: 'A4' } }),
});
const pdf = await response.arrayBuffer();

Puppeteerからの詳しい移行手順はPuppeteer→PDF API移行ガイドをご覧ください。

コード比較:同じ請求書を生成する

実際に同じ請求書テンプレートを、ライブラリ方式とAPI方式の両方で生成するコードを比較します。

Puppeteer(ライブラリ方式)

const puppeteer = require('puppeteer');

async function generateInvoicePdf(invoiceData) {
  const html = buildInvoiceHtml(invoiceData); // HTMLテンプレート生成

  const browser = await puppeteer.launch({
    headless: 'new',
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
  });

  const page = await browser.newPage();
  await page.setContent(html, { waitUntil: 'networkidle0' });

  const pdfBuffer = await page.pdf({
    format: 'A4',
    margin: { top: '20mm', right: '15mm', bottom: '20mm', left: '15mm' },
    printBackground: true,
    displayHeaderFooter: true,
    headerTemplate: '<span></span>',
    footerTemplate: '<div style="font-size:8px;text-align:center;width:100%;">Page <span class="pageNumber"></span></div>',
  });

  await browser.close();
  return pdfBuffer;
}

FUNBREW PDF API(API方式)

async function generateInvoicePdf(invoiceData) {
  const html = buildInvoiceHtml(invoiceData); // 同じHTMLテンプレートを使用

  const response = await fetch('https://pdf.funbrew.cloud/api/v1/generate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FUNBREW_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      html,
      options: {
        format: 'A4',
        margin: { top: '20mm', right: '15mm', bottom: '20mm', left: '15mm' },
        printBackground: true,
      },
    }),
  });

  return await response.arrayBuffer();
}

HTMLテンプレートの buildInvoiceHtml()まったく同じものを使えます。変更点はPDF変換処理の部分だけです。Playgroundで実際にHTMLを入力してPDF出力を試すこともできます。

Python(ReportLab vs API)

# ReportLab — Pythonでプログラム的にPDFを構築
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas

def generate_invoice(data, output_path):
    c = canvas.Canvas(output_path, pagesize=A4)
    c.setFont("Helvetica-Bold", 20)
    c.drawString(50, 780, "INVOICE")
    c.setFont("Helvetica", 12)
    c.drawString(50, 750, f"Invoice #: {data['number']}")
    c.drawString(50, 730, f"Date: {data['date']}")
    # ... 座標を計算しながら1行ずつ配置
    c.save()
# FUNBREW PDF API — HTMLテンプレートでPDF生成
import requests

def generate_invoice(data):
    html = render_template("invoice.html", data=data)
    response = requests.post(
        "https://pdf.funbrew.cloud/api/v1/generate",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"html": html, "options": {"format": "A4"}},
    )
    return response.content

ReportLabは座標ベースでPDFを構成するため、レイアウト変更のたびに座標計算のやり直しが必要です。HTML/CSSベースのAPIなら、デザインの修正はCSSの変更だけで完結します。CSSによるPDFスタイリングのコツはHTML to PDF CSSテクニック集を参照してください。

まとめ

PDF生成のAPI方式とライブラリ方式は、どちらかが絶対的に優れているわけではありません。

  • 小規模・英語のみ・既存資産あり → ライブラリ方式を継続
  • 日本語対応・スケーラビリティ・開発速度 → API方式が有利

プロジェクトの初期段階であれば、まずAPIで素早くMVPを構築し、特殊な要件が見えてきた段階でライブラリへの移行を検討する——という進め方も実用的です。

FUNBREW PDFは無料プランから試せるので、まずはPlaygroundで実際のPDF出力を確認してみてください。各言語のセットアップ方法はクイックスタートガイドにまとめています。

関連記事

Powered by FUNBREW PDF