2026/05/09

HTML to PDF変換の全手法を2026年版で比較:pros・cons・コード付き

HTML to PDF比較wkhtmltopdfPuppeteerPDF API

HTMLをPDFに変換するツールは多数存在します。「解決済みの問題」と言えますが、ユースケースに合ったツールを選ぶのは単純ではありません。各手法はレンダリング精度・CSSサポート・運用複雑性・コストで異なるトレードオフをしているからです。

この記事では2026年時点で利用可能な主要なHTML→PDF変換手法を、正直なpros/consと実際のコードとともに紹介します。

PuppeteerとマネージドAPIの比較に特化した記事はPuppeteer vs PDF APIをご覧ください。Chromiumベースの手法すべてに共通するCSSのコツはHTML to PDF CSSのコツをご覧ください。

各手法の概要

手法 エンジン CSSサポート 運用複雑性 セルフホスト
ブラウザの印刷ダイアログ Chromium / WebKit 完全 なし(手動)
wkhtmltopdf QtWebKit(アーカイブ済み) 部分的
Puppeteer / Playwright Chromium 完全
WeasyPrint Python独自レンダラー 良好 低〜中
Gotenberg Chromium + LibreOffice 完全
マネージドPDF API Chromium 完全 非常に低 不要

1. ブラウザの印刷ダイアログ

最もシンプルな方法です。JavaScriptでwindow.print()を呼ぶと、ブラウザのネイティブ印刷ダイアログが開き、ユーザーがPDFとして保存できます。

// 印刷ダイアログを表示
window.print();

// 印刷ボタンに設定
document.getElementById('print-btn').addEventListener('click', () => {
  window.print();
});

CSS @media print ルールでレイアウトを制御します。

@media print {
  .no-print { display: none; }
  body { font-size: 12pt; }
  @page { margin: 20mm; size: A4; }
}

Pros:

  • セットアップ不要・コスト不要
  • 完全なブラウザレンダリングエンジンを使用
  • サーバーサイドのコード不要

Cons:

  • ユーザーが手動で保存する必要がある(自動化不可)
  • 印刷ダイアログの外観はブラウザとOSによって異なる
  • ページブレークの制御が難しい
  • ヘッダー・フッター・複数ページのレイアウトが困難
  • サーバーから無音でトリガーできない

最適なユースケース: 「PDFとして保存」ボタンで十分で、自動化が不要な開発者ツールや社内ダッシュボード。

2. wkhtmltopdf

QtWebKitレンダリングエンジンに基づくコマンドラインツール。長年にわたりサーバーサイドのHTML→PDF変換の主流でした。

# インストール(Debian/Ubuntu)
sudo apt-get install wkhtmltopdf

# 基本的な変換
wkhtmltopdf input.html output.pdf

# オプション付き
wkhtmltopdf \
  --page-size A4 \
  --margin-top 20mm \
  --margin-bottom 20mm \
  --margin-left 15mm \
  --margin-right 15mm \
  --encoding utf-8 \
  invoice.html invoice.pdf
# Pythonラッパー
import subprocess

def html_to_pdf(html_path: str, output_path: str) -> None:
    subprocess.run([
        'wkhtmltopdf',
        '--page-size', 'A4',
        '--margin-top', '20mm',
        '--margin-bottom', '20mm',
        html_path,
        output_path,
    ], check=True)

Pros:

  • 軽量で高速(Chromiumベースのツールよりリソース消費が少ない)
  • シンプルなCLIインターフェース
  • 成熟しており、ドキュメントが豊富

Cons:

  • 2023年にアーカイブ済み — セキュリティパッチやバグ修正がない
  • QtWebKitエンジンはモダンブラウザより7〜8年遅れている
  • CSS GridとFlexboxのサポートが不完全
  • JavaScript実行が必要なページをレンダリングできない
  • CJKフォントのサポートには手動でのフォントインストールが必要
  • 新規プロジェクトには非推奨

最適なユースケース: まだ移行していないwkhtmltopdf使用中のレガシーシステム。移行ガイドはwkhtmltopdf移行ガイドをご覧ください。

3. Puppeteer(Node.js)

Puppeteerはheadless Chromiumを操作するNode.jsライブラリです。もともとブラウザ自動化とテスト向けに作られており、PDF生成はその機能の一つです。

const puppeteer = require('puppeteer');

async function generatePdf(html) {
  const browser = await puppeteer.launch({
    headless: 'new',
    args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
  });

  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,
  });

  await browser.close();
  return pdf;
}

Pros:

  • モダンなCSS完全サポート(Grid・Flexbox・カスタムプロパティ)
  • PDF生成前にJavaScriptを実行できる
  • 大きなコミュニティとエコシステム
  • Chromeと同一のレンダリング

Cons:

  • Chromiumのインストールとバージョン管理が必要
  • プロセスあたり200〜500MBのメモリ消費
  • コールドスタート: 1〜3秒(Lambda上では8〜15秒)
  • 同時処理にはブラウザプールが必要
  • Dockerイメージが1GB以上に膨張
  • PDF生成専用ではない

最適なユースケース: ブラウザテストでPuppeteerを既に使用していて低〜中規模のPDF生成が必要な場合、またはエクスポート前にpage.evaluate()でJavaScriptを実行する必要がある場合。

4. Playwright(Node.js・Python・.NET・Java)

PlaywrightはMicrosoftのブラウザ自動化ライブラリです。Chromium・Firefox・WebKitをサポートし、PuppeteerよりクリーンなAPIを提供します。PDF生成ではChromiumを使うため、出力はPuppeteerと同一です。

// Node.js
const { chromium } = require('playwright');

async function generatePdf(html) {
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

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

  await browser.close();
  return pdf;
}
# Python
import asyncio
from playwright.async_api import async_playwright

async def generate_pdf(html: str) -> bytes:
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.set_content(html, wait_until='networkidle')
        pdf = await page.pdf(
            format='A4',
            margin={'top': '20mm', 'bottom': '20mm',
                    'left': '15mm', 'right': '15mm'},
            print_background=True,
        )
        await browser.close()
        return pdf

Pros:

  • PuppeteerよりクリーンなAPI
  • 多言語サポート(Node.js・Python・.NET・Java)
  • 活発な開発・メンテナンス
  • モダンなCSS完全サポート

Cons:

  • Puppeteerと同じ本質的な問題: Chromium管理・200〜500MBメモリ・コールドスタート
  • playwright install chromiumでPuppeteerより大きなChromiumをダウンロード
  • PDF生成専用ではない

最適なユースケース: PuppeteerよりPythonや.NETを好む場合、またはテストでFirefox/WebKitのレンダリングが必要な場合。運用上の問題が痛点なら、マネージドAPIへの移行が費用対効果が高い選択肢です。PlaywrightからPDF API移行ガイドをご覧ください。

5. WeasyPrint

WeasyPrintは独自のレンダリングエンジン(Chromiumではない)を使ってHTMLとCSSをPDFに変換するPythonライブラリです。CSS Paged Media仕様を直接実装しています。

# インストール
pip install weasyprint

# CLI
weasyprint input.html output.pdf
from weasyprint import HTML, CSS

def generate_pdf(html: str, css: str = None) -> bytes:
    html_doc = HTML(string=html)
    stylesheets = [CSS(string=css)] if css else []
    return html_doc.write_pdf(stylesheets=stylesheets)

WeasyPrintはCSS Paged Mediaの機能(@pageルール・名前付きページ・ランニング要素)のサポートが優れています。

@page {
  size: A4;
  margin: 20mm;

  @bottom-center {
    content: "Page " counter(page) " of " counter(pages);
  }
}

/* ランニングヘッダー/フッター */
.header { position: running(header); }
@page { @top-center { content: element(header); } }

Pros:

  • CSS Paged Mediaのサポートが優秀(ヘッダー・フッター・ページカウンター)
  • 軽量 — Chromium不要
  • 純粋なPython — Django・Flask・FastAPIへの統合が容易
  • 複雑な複数ページレイアウトのドキュメントに強い

Cons:

  • JavaScriptの実行をサポートしない
  • CSSサポートはブラウザと同一ではない(一部のモダンプロパティが未対応)
  • CJKフォントサポートにはフォントのインストールが必要
  • 多くのCSSルールを持つ複雑なページではChromiumより遅い

最適なユースケース: CSS Paged Mediaの機能が重要で、JavaScriptレンダリングが不要な構造化ドキュメント(レポート・書類・契約書)を生成するPythonアプリケーション。

6. Gotenberg

GotenbergはChromiumとLibreOfficeをラップして文書変換用のREST APIを公開するオープンソースのDockerサービスです。

# DockerでGotenbergを起動
docker run --rm -p 3000:3000 gotenberg/gotenberg:8

# HTMLをPDFに変換
curl \
  --request POST http://localhost:3000/forms/chromium/convert/html \
  --form files=@index.html \
  --form marginTop=20 \
  --form marginBottom=20 \
  -o output.pdf
import requests

def generate_pdf_gotenberg(html: str) -> bytes:
    response = requests.post(
        'http://localhost:3000/forms/chromium/convert/html',
        files={'files': ('index.html', html, 'text/html')},
        data={'marginTop': '20', 'marginBottom': '20'},
    )
    response.raise_for_status()
    return response.content

Pros:

  • 言語に依存しないREST API
  • Chromiumの完全なレンダリング機能
  • Word・Excel・PowerPointのPDF変換もサポート(LibreOffice経由)
  • ローカル開発はDockerで一発起動

Cons:

  • Dockerが必要 — サーバーレス環境での実行が困難
  • スケーリングを自前で管理(コンテナの起動・スケールアウト)
  • 大きなDockerイメージ(Chromium + LibreOffice)
  • CJKフォントサポートには追加のDocker設定が必要

最適なユースケース: 言語に依存しないセルフホストのREST APIが必要で、Officeドキュメントの変換も必要なチーム。スケーリングを管理するKubernetesデプロイ。サーバーレスには不向き。

7. マネージドPDF API

マネージドPDF API(例:FUNBREW PDF)はホスト型サービスです。HTMLをPOSTするとPDFバイトが返ってきます。サーバーインフラの管理は不要です。

// Node.js
async function generatePdf(html) {
  const response = await fetch('https://pdf.funbrew.cloud/api/v1/pdf/generate', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.FUNBREW_PDF_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      html,
      options: {
        format: 'A4',
        margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
        print_background: true,
      },
    }),
  });
  if (!response.ok) throw new Error(`API error: ${response.status}`);
  return Buffer.from(await response.arrayBuffer());
}
# Python
import os, requests

def generate_pdf(html: str) -> bytes:
    resp = requests.post(
        'https://pdf.funbrew.cloud/api/v1/pdf/generate',
        headers={
            'X-API-Key': os.environ['FUNBREW_PDF_API_KEY'],
            'Content-Type': 'application/json',
        },
        json={
            'html': html,
            'options': {
                'format': 'A4',
                'margin': {'top': '20mm', 'bottom': '20mm',
                           'left': '15mm', 'right': '15mm'},
                'print_background': True,
            },
        },
        timeout=30,
    )
    resp.raise_for_status()
    return resp.content

Pros:

  • インフラ管理ゼロ — APIキーだけで開始
  • Chromiumと同等のレンダリング(Puppeteerと同じCSSサポート)
  • 同時リクエストの自動スケーリング
  • 自サーバー側にコールドスタートなし
  • 日本語・CJKフォントを標準搭載
  • 小さなDockerイメージ(自サーバーにChromiumが不要)
  • Webhook・テンプレートエンジン・メール配信を内蔵

Cons:

  • 大規模ではリクエスト単位のコストが発生
  • 外部サービスへの依存
  • HTMLをサードパーティのサーバーに送信する(データポリシーの確認が必要)

最適なユースケース: PDF生成が重要な機能になっているほとんどの本番アプリケーション、サーバーレス環境、Chromiumインフラを維持したくないチーム。Playgroundでレンダリング品質を確認してから導入を検討してください。

手法の選び方

判断基準

自動化が必要か?
  不要 → ブラウザの印刷ダイアログ

エクスポート前にJavaScriptの実行が必要か?
  要 → Puppeteer・Playwright・またはマネージドAPI

主要言語は?
  Python(JS不要) → WeasyPrint またはマネージドAPI
  Python(JS必要) → Playwright(Python)またはマネージドAPI
  Node.js          → Puppeteer・Playwright・またはマネージドAPI
  PHP / Ruby / Go  → マネージドAPI またはGotenberg

Officeファイルの変換も必要か?
  要 → Gotenberg

サーバーレス(Lambda・Vercel・CF Workers)か?
  要 → マネージドAPIを強く推奨

月30件未満か?
  要 → マネージドAPIの無料枠 またはPuppeteer

外部へのHTML送信を禁止するポリシーがあるか?
  要 → Puppeteer・Playwright・またはGotenbergのセルフホスト

インフラ管理をゼロにしたいか?
  要 → マネージドAPI

まとめ表

手法 セットアップ メモリ サーバーレス CJK コスト
ブラウザ印刷 なし N/A ネイティブ 無料
wkhtmltopdf 困難 手動 無料(非推奨)
Puppeteer 200〜500MB 困難 手動 サーバーコスト
Playwright 200〜500MB 困難 手動 サーバーコスト
WeasyPrint 容易 手動 無料
Gotenberg Docker 困難 Docker設定 無料(セルフホスト)
マネージドAPI なし < 10MB 容易 標準搭載 リクエスト単位

まとめ

2026年時点では、新規の本番アプリケーションにはマネージドPDF APIがデフォルトの推奨です。Puppeteerと同等のChromiumレンダリング品質を、運用負荷なしで提供します。セルフホストを選ぶ強い理由は、データ所在地の要件か、サーバーサイドレンダリングに移せないJavaScript実行が必要な場合に限られます。

既にPuppeteerやwkhtmltopdfを規模で運用しているチームには、メンテナンスエンジニアリング時間を考慮すると、マネージドAPIの方がほぼすべての現実的な規模でコスト効率が高くなります。Playgroundでテンプレートのレンダリング品質をテストし、無料プランを確認してから判断してください。

関連リンク

Powered by FUNBREW PDF