NaN/NaN/NaN

PDF生成において「wkhtmltopdfで十分なのか、それともChromiumに移行すべきなのか」は、開発者がよく悩むポイントです。

この記事では、両エンジンの違いを具体的なユースケースとともに解説し、プロジェクトに合った選び方を提案します。

wkhtmltopdfとは

wkhtmltopdfは、QtWebKitエンジンをベースにしたオープンソースのHTML→PDF変換ツールです。2012年から使われており、多くのプロジェクトで採用されています。

特徴

  • 高速: Chromiumより2〜5倍速い
  • 軽量: メモリ消費が少ない(50〜100MB程度)
  • シンプル: コマンドラインで即使える
  • 安定: 長年の実績

制限事項

  • CSS Grid / Flexboxの対応が不完全
  • JavaScript実行の制限
  • WebKitの古いバージョンがベース
  • メンテナンスの停滞

Chromiumエンジンとは

Puppeteer、Playwright、Gotenbergなどは、内部でChromium(Google Chromeのオープンソース版)を使ってPDFを生成します。

特徴

  • 完全なCSS対応: Grid、Flexbox、CSS変数、calc()すべてOK
  • JavaScript実行: SPAやChartのレンダリングも可能
  • 最新Web標準: ブラウザと同じ描画結果
  • @media print対応: 印刷用CSSが正確に反映される

制限事項

  • 起動が遅い(コールドスタートで1〜3秒)
  • メモリ消費が大きい(200〜500MB)
  • Dockerやプロセス管理が必要

品質比較

CSS対応

<!-- このレイアウトはwkhtmltopdfでは崩れる -->
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
  <div>左カラム</div>
  <div>右カラム</div>
</div>
CSS機能 wkhtmltopdf Chromium
Flexbox 一部対応 完全対応
CSS Grid 非対応 完全対応
CSS変数 非対応 完全対応
calc() 一部対応 完全対応
@media print 一部対応 完全対応
Webフォント 要設定 自動読込
WebP / AVIF 画像 非対応 完全対応

画像形式の対応

JPEG / PNG / GIF は両エンジンで問題なく利用できます。一方、WebP や AVIF といった新しい形式は wkhtmltopdf(QtWebKit)では描画されず、PDF上では画像が欠落します。ChromiumはブラウザがサポートしているのでWebP/AVIFもそのまま埋め込めます。

<!-- wkhtmltopdf では表示されない(Chromiumのみ) -->
<img src="photo.webp" alt="写真">

<!-- 両エンジンで表示できる -->
<img src="photo.jpg" alt="写真">

FUNBREW PDFでWebP画像を含むHTMLを扱う場合は、"engine": "quality" を指定してください。

日本語フォント

wkhtmltopdfでは日本語フォントの設定が必要で、環境によっては文字化けすることがあります。Chromiumは環境にインストールされたフォントを自動で使用するため、設定不要です。

速度

簡単なHTMLの場合(実測値):

内容 wkhtmltopdf Chromium
1ページのテキスト 0.3秒 1.2秒
テーブル10行 0.5秒 1.5秒
画像入り5ページ 1.2秒 2.8秒
CSSリッチなレポート 1.5秒 2.5秒

wkhtmltopdfが常に速いですが、その差は用途によっては許容範囲です。

用途別の推奨

wkhtmltopdfが向いている場面

  • シンプルなテキスト/表のPDF(領収書、シンプルな帳票)
  • 大量生成が必要(月に数千〜数万件)
  • レスポンスタイムが重要(リアルタイム生成)
  • サーバーリソースが限られている

Chromiumが向いている場面

  • デザイン性の高い帳票(CSS Grid/Flexboxを使用)
  • グラフやチャートを含むレポート(JavaScript描画が必要)
  • Web画面そのままをPDF化(URL→PDF変換)
  • 印刷用CSSを正確に反映したい

APIコール例

FUNBREW PDFのAPIを使ってエンジンを切り替える方法を、各言語の実装例で解説します。

cURL

# Fast エンジン(wkhtmltopdf)— 高速生成
curl -X POST https://pdf.funbrew.cloud/api/v1/pdf/from-html \
  -H "Authorization: Bearer $FUNBREW_PDF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>請求書</h1><p>合計: ¥10,000</p>",
    "options": {
      "engine": "fast",
      "format": "A4"
    }
  }' \
  -o invoice.pdf

# Quality エンジン(Chromium)— CSS Grid対応が必要な場合
curl -X POST https://pdf.funbrew.cloud/api/v1/pdf/from-html \
  -H "Authorization: Bearer $FUNBREW_PDF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<div style=\"display:grid;grid-template-columns:1fr 1fr\">...</div>",
    "options": {
      "engine": "quality",
      "format": "A4"
    }
  }' \
  -o report.pdf

Python

import httpx
import os

FUNBREW_PDF_API_KEY = os.environ["FUNBREW_PDF_API_KEY"]

def generate_pdf(html: str, engine: str = "fast") -> bytes:
    """
    engine: "fast" (wkhtmltopdf) or "quality" (Chromium)
    """
    response = httpx.post(
        "https://pdf.funbrew.cloud/api/v1/pdf/from-html",
        headers={
            "Authorization": f"Bearer {FUNBREW_PDF_API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "html": html,
            "options": {
                "engine": engine,
                "format": "A4",
            },
        },
        timeout=30.0,
    )
    response.raise_for_status()
    return response.content

# 請求書(シンプルなHTML → fastで十分)
invoice_html = "<h1>請求書</h1><table>...</table>"
pdf_bytes = generate_pdf(invoice_html, engine="fast")

with open("invoice.pdf", "wb") as f:
    f.write(pdf_bytes)

# グラフ入りレポート(CSS Grid使用 → qualityが必要)
report_html = """
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 24px;">
  <div><canvas id="chart1"></canvas></div>
  <div><canvas id="chart2"></canvas></div>
</div>
"""
pdf_bytes = generate_pdf(report_html, engine="quality")

Node.js

const fs = require('fs');

async function generatePdf(html, engine = 'fast') {
  const response = await fetch('https://pdf.funbrew.cloud/api/v1/pdf/from-html', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FUNBREW_PDF_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      html,
      options: {
        engine,   // 'fast' (wkhtmltopdf) or 'quality' (Chromium)
        format: 'A4',
      },
    }),
  });

  if (!response.ok) {
    throw new Error(`PDF generation failed: ${response.statusText}`);
  }

  return Buffer.from(await response.arrayBuffer());
}

// 用途ごとに使い分け
async function main() {
  // 領収書: シンプルなHTML → fast
  const receiptHtml = '<h1>領収書</h1><p>¥5,000</p>';
  const receiptPdf = await generatePdf(receiptHtml, 'fast');
  fs.writeFileSync('receipt.pdf', receiptPdf);

  // 月次レポート: Chart.js使用 → quality
  const reportHtml = `
    <html>
      <head><script src="https://cdn.jsdelivr.net/npm/chart.js"></script></head>
      <body>
        <h1>月次レポート</h1>
        <canvas id="salesChart" width="400" height="200"></canvas>
        <script>
          new Chart(document.getElementById('salesChart'), {
            type: 'bar',
            data: { labels: ['1月','2月','3月'], datasets: [{ data: [65,59,80] }] }
          });
        </script>
      </body>
    </html>
  `;
  const reportPdf = await generatePdf(reportHtml, 'quality');
  fs.writeFileSync('report.pdf', reportPdf);
}

main();

ユースケース別フロー

請求書生成(wkhtmltopdf / fast)

請求書は通常テキストと表で構成されており、wkhtmltopdfで十分な品質が得られます。

注文確定イベント
    ↓
請求データをJSON生成
    ↓
generate_pdf(html, engine="fast")   ← 0.3〜0.5秒で完了
    ↓
PDFをS3保存 + メール送信

詳細な実装例は請求書PDFの自動生成で解説しています。また請求書自動化のユースケースも参照してください。

月次レポート(Chromium / quality)

グラフやダッシュボードのスクリーンショットが必要な場合はChromiumが必須です。

月末バッチ実行
    ↓
データ集計 → グラフHTML組み立て(Chart.js等)
    ↓
generate_pdf(html, engine="quality")  ← 2〜3秒かかるが品質優先
    ↓
PDFをダッシュボードに保存 + 管理者へ配信

レポート自動化のユースケースでグラフ入りレポートの実例を紹介しています。

証明書・修了証(Chromium / quality)

フォント装飾や複雑なレイアウトを使う証明書にはChromiumが適しています。

修了イベント(試験合格・研修完了など)
    ↓
テンプレートに受講者名・修了日を差し込む
    ↓
generate_pdf(html, engine="quality")  ← Flexboxレイアウト対応
    ↓
PDFをメール送付 + マイページに保存

証明書発行のユースケースで実装パターンを紹介しています。

大量バッチ生成(wkhtmltopdf / fast)

月末の明細書一括送付など、数千件規模では速度が重要になります。

import asyncio
import httpx

async def batch_generate(records: list[dict]) -> list[bytes]:
    """非同期で並列生成(fastエンジンで高スループット)"""
    async with httpx.AsyncClient() as client:
        tasks = [
            client.post(
                "https://pdf.funbrew.cloud/api/v1/pdf/from-html",
                headers={"Authorization": f"Bearer {API_KEY}"},
                json={"html": build_html(r), "options": {"engine": "fast"}},
                timeout=30.0,
            )
            for r in records
        ]
        responses = await asyncio.gather(*tasks)
    return [r.content for r in responses]

FUNBREW PDFでの使い分け

FUNBREW PDFでは、APIリクエスト時にエンジンを選択できます。

{
  "html": "<h1>Hello</h1>",
  "options": {
    "engine": "fast"
  }
}
パラメータ エンジン 用途
"engine": "fast" wkhtmltopdf 高速生成、シンプルなHTML
"engine": "quality" Chromium/Gotenberg 高品質、モダンCSS

同じテンプレートでも、エンジンを切り替えるだけで速度と品質のバランスを調整できます。

プランごとの利用可能エンジン

プラン Fast (wkhtmltopdf) Quality (Chromium)
Free 利用可 Playgroundのみ
Starter 利用可 Playgroundのみ
Basic〜 利用可 利用可

移行コストの現実:wkhtmltopdfからChromiumへ

wkhtmltopdfを使っているプロジェクトがChromiumに移行する際に発生するコストを把握しておくことが重要です。

移行の主なハードル

1. インフラの変更

wkhtmltopdfは単一バイナリで動作しますが、ChromiumをPuppeteer/Playwrightで操作するにはNode.jsランタイムと200〜500MBのChromiumバイナリが必要です。Dockerイメージのサイズが数百MB増加し、コールドスタートが遅くなります。

# wkhtmltopdfベースのDockerイメージ(約180MB)
FROM surnet/alpine-wkhtmltopdf:3.1.0-0.12.6-full

# Puppeteerベースのイメージ(約800MB)
FROM node:20-slim
RUN apt-get update && apt-get install -y chromium

2. 本番運用の複雑さ

Chromiumはサンドボックス設定、メモリ管理、プロセス監視が必要です。特にDockerコンテナ上では --no-sandbox フラグの安全な設定や、並行処理時のメモリ上限管理がトラブルになりやすいポイントです。PDF API本番運用チェックリストでも詳しく解説していますが、Chromiumの安定稼働には継続的なメンテナンスが伴います。

3. コスト

項目 wkhtmltopdf Chromium
インフラコスト 低(小メモリで動作) 高(メモリ500MB+)
開発・保守コスト 低(シンプル) 高(Chromium管理が複雑)
バージョン管理 ほぼ不要 Puppeteer/Chrome更新が必要
セキュリティパッチ 年数回 毎月Chrome更新

この複雑さを避けたい場合、マネージドのPDF APIサービスを使うのが合理的な選択です。PuppeteerからFUNBREW PDF APIへの移行ガイドでは、既存のChromiumベースのコードをAPIに置き換える手順を解説しています。

エンジン選択のトラブルシューティング

よくある問題と対処法

問題1: wkhtmltopdfで日本語が文字化けする

wkhtmltopdfはフォントの自動検出が弱く、日本語フォントが未インストールだと文字化けします。

# Ubuntuでの日本語フォントインストール
apt-get install fonts-noto-cjk

# wkhtmltopdfコマンドで明示的にフォントを指定
wkhtmltopdf --encoding utf-8 input.html output.pdf

日本語PDF生成ガイドでフォント設定の詳細を解説しています。Chromiumは環境のフォントを自動参照するため、同じ問題が起きにくいです。

問題2: CSSレイアウトがwkhtmltopdfで崩れる

CSS Gridを使ったレイアウトはwkhtmltopdfでは動作しません。Flexboxも部分的なサポートにとどまります。

/* wkhtmltopdfでは崩れる(Chromiumのみ対応) */
.report-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

/* wkhtmltopdfでも動作する代替手法 */
.report-table {
  width: 100%;
  table-layout: fixed;
}
.report-cell {
  width: 33.3%;
  vertical-align: top;
  padding: 12px;
}

詳細な回避策はHTML to PDF CSS最適化ガイドを参照してください。

問題3: Chromiumで特定ページの改ページが崩れる

/* 改ページを制御するCSS */
.section {
  page-break-before: always; /* または break-before: page; */
}
.no-break {
  page-break-inside: avoid;
}

PDF出力トラブルシューティングで、改ページ問題の原因特定と解決策を体系的にまとめています。

2026年時点でのエンジン選択状況

wkhtmltopdfのメンテナンス状況

wkhtmltopdfは事実上メンテナンスが停滞しており、GitHubリポジトリへのコミットも激減しています。QtWebKitという古いレンダリングエンジンを使用しており、現代のWebスタンダード(CSS Grid、WebP画像、モダンJavaScript)への対応は期待できません。

新規プロジェクトでのwkhtmltopdf採用は推奨しません。 既存システムでの継続使用は許容範囲ですが、機能追加の際にChromiumへの移行を検討するタイミングといえます。

Chromiumエンジンの動向

Puppeteer v22(2024年〜)以降、Chrome for Testingとの統合が進み、特定バージョンのChromeを固定して使えるようになりました。これにより、予期せぬアップデートによる描画の変化を防げます。

// Puppeteer v22以降: Chrome for Testingで固定バージョンを使用
const browser = await puppeteer.launch({
  executablePath: '/path/to/chrome-for-testing',
  args: ['--no-sandbox', '--disable-dev-shm-usage'],
});

マネージドAPIという第3の選択肢

wkhtmltopdfもChromiumも自前で管理せず、FUNBREW PDFのようなマネージドAPIを使うという選択があります。

  • エンジンのインストール・更新・セキュリティパッチが不要
  • "engine": "fast"(wkhtmltopdf相当)と"engine": "quality"(Chromium相当)をAPIパラメータで切り替え可能
  • 月次コスト予測が立てやすく、スパイク時も安定

API料金と自前運用のコスト比較はPDF API料金比較で詳しく解説しています。

エラーハンドリングの違い

wkhtmltopdfとChromiumではエラーの種類と対処法が異なります。PDF APIエラーハンドリングガイドでは両エンジン共通のエラーパターンとAPIを使った場合のリトライ戦略を解説しています。

エラー wkhtmltopdf Chromium
フォント未検出 文字化けしてもエラーにならない(サイレント失敗) コンソールに警告が出る
JavaScript実行エラー 無視される エラーになることがある
タイムアウト コマンドが終了しないことがある page.goto() でタイムアウト制御可能
メモリ不足 クラッシュ OOMキラーに落とされる

まとめ

  • 速度優先・シンプルなHTML → wkhtmltopdf(fast
  • 品質優先・モダンCSS → Chromium(quality
  • 両方使い分けたい → FUNBREW PDFのデュアルエンジン
  • 新規プロジェクト → wkhtmltopdfの採用は避け、ChromiumベースまたはマネージドAPIを選択

迷ったらまずfastで試して、表示が崩れる場合にqualityに切り替えるのが効率的です。

無料で試す →

関連リンク

Powered by FUNBREW PDF