2026/04/18

Python PDF生成完全ガイド|ReportLab・WeasyPrint・API比較と実装例

PythonPDF生成WeasyPrintReportLabチュートリアル

「PythonでPDFを生成したい」という要件は、請求書・レポート・証明書・帳票など、あらゆるWebアプリやデータパイプラインで発生します。Pythonにはライブラリが豊富にある一方、それぞれに得意・不得意があります。

この記事では、Pythonプロジェクトでよく使われる6つのアプローチを実際に動くコード例とともに比較し、ユースケース別の選び方を解説します。FUNBREW PDF APIを使う方法を中心に、Django・FastAPI・Flask連携、バッチ処理まで幅広くカバーします。

PythonでのPDF生成:6つのアプローチ比較

まず主要な手法を一覧で比較します。

アプローチ HTMLサポート CSS精度 依存関係 サーバーレス おすすめ用途
FUNBREW PDF API 完全 高(Chromium) requestsのみ 対応 本番環境・SaaS・複雑レイアウト
ReportLab なし 対応 数値・グラフ・データレポート
WeasyPrint 完全 中〜高 大(GTK依存) 困難 HTMLメール→PDF・中規模アプリ
xhtml2pdf XHTML 対応 小規模・シンプルなレイアウト
pdfkit(wkhtmltopdf) 完全 wkhtmltopdfバイナリ 困難 既存wkhtmltopdf環境の維持
Playwright for Python 完全 高(Chromium) Chromiumバイナリ 困難 ローカル・テスト自動化兼用

複雑なHTMLレイアウト(グラフ・表・日本語フォント)を含む業務PDFには PDF API が最も適しています。PDF APIとライブラリの比較で詳しく解説しています。

1. FUNBREW PDF API(推奨)

インストールと基本設定

pip install requests python-dotenv
# pdf_client.py
import os
import requests
from dotenv import load_dotenv

load_dotenv()

FUNBREW_API_KEY = os.environ["FUNBREW_API_KEY"]
FUNBREW_API_URL = os.getenv("FUNBREW_API_URL", "https://api.pdf.funbrew.cloud/v1")

def html_to_pdf(
    html: str,
    engine: str = "quality",   # "quality"(Chromium)または "fast"(wkhtmltopdf)
    format: str = "A4",
    landscape: bool = False,
    margin: dict | None = None,
) -> bytes:
    """
    HTML文字列をPDFバイナリに変換する。

    Args:
        html: PDF化するHTML文字列
        engine: "quality"(Chromium)または "fast"(wkhtmltopdf)
        format: 用紙サイズ("A4", "Letter", "Legal" など)
        landscape: 横向きにするか
        margin: 余白設定(top/bottom/left/right をmm単位で指定)

    Returns:
        PDFのバイナリデータ(bytes)
    """
    if margin is None:
        margin = {"top": "20mm", "bottom": "20mm", "left": "15mm", "right": "15mm"}

    response = requests.post(
        f"{FUNBREW_API_URL}/pdf/from-html",
        headers={
            "Authorization": f"Bearer {FUNBREW_API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "html": html,
            "engine": engine,
            "format": format,
            "landscape": landscape,
            "margin": margin,
        },
        timeout=30,
    )
    response.raise_for_status()
    return response.content

APIドキュメントでオプションの完全仕様を確認できます。

基本的な使い方

# generate_basic.py
from pdf_client import html_to_pdf

html = """<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <style>
    body { font-family: 'Noto Sans JP', sans-serif; padding: 40px; color: #1e293b; }
    h1 { color: #2563eb; }
  </style>
</head>
<body>
  <h1>Hello, PDF!</h1>
  <p>PythonからFUNBREW PDF APIでPDFを生成しました。</p>
</body>
</html>"""

pdf_bytes = html_to_pdf(html)

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

print(f"PDF生成完了: {len(pdf_bytes):,} bytes")

請求書PDFの実用例

# invoice_generator.py
from datetime import date
from pdf_client import html_to_pdf


def build_invoice_html(
    customer_name: str,
    amount: int,
    items: list[dict] | None = None,
    company_name: str = "株式会社FUNBREW",
) -> str:
    tax = int(amount * 0.1)
    total = amount + tax
    invoice_number = f"INV-{date.today().strftime('%Y%m%d')}-001"
    issue_date = date.today().strftime("%Y年%m月%d日")

    if not items:
        items = [{"name": "サービス利用料", "quantity": 1, "price": amount}]

    rows = "".join(
        f"<tr><td>{item['name']}</td>"
        f"<td style='text-align:right'>{item['quantity']}</td>"
        f"<td style='text-align:right'>¥{item['price']:,}</td>"
        f"<td style='text-align:right'>¥{item['price'] * item['quantity']:,}</td></tr>"
        for item in items
    )

    return f"""<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <style>
    @page {{ size: A4; margin: 20mm 15mm; }}
    * {{ box-sizing: border-box; margin: 0; padding: 0; }}
    body {{
      font-family: 'Noto Sans JP', 'Hiragino Sans', sans-serif;
      font-size: 12px; color: #1e293b;
      -webkit-print-color-adjust: exact; print-color-adjust: exact;
    }}
    .header {{ display: flex; justify-content: space-between;
      border-bottom: 3px solid #2563eb; padding-bottom: 16px; margin-bottom: 24px; }}
    .title {{ font-size: 28px; font-weight: 700; color: #2563eb; }}
    table {{ width: 100%; border-collapse: collapse; margin-top: 16px; }}
    th {{ background: #dbeafe; padding: 10px; text-align: left; }}
    td {{ padding: 10px; border-bottom: 1px solid #e2e8f0; }}
    .total {{ text-align: right; margin-top: 16px; }}
    .total-amount {{ font-size: 22px; font-weight: 700; color: #2563eb; }}
  </style>
</head>
<body>
  <div class="header">
    <div>
      <div class="title">請求書</div>
      <div>請求番号: {invoice_number}</div>
      <div>発行日: {issue_date}</div>
    </div>
    <div style="text-align:right"><strong>{company_name}</strong></div>
  </div>
  <p><strong>{customer_name} 御中</strong></p>
  <table>
    <thead>
      <tr><th>品目</th><th>数量</th><th>単価</th><th>小計</th></tr>
    </thead>
    <tbody>{rows}</tbody>
  </table>
  <div class="total">
    <p>小計: ¥{amount:,}</p>
    <p>消費税 (10%): ¥{tax:,}</p>
    <p class="total-amount">合計: ¥{total:,}</p>
  </div>
</body>
</html>"""


def generate_invoice_pdf(customer_name: str, amount: int, items=None) -> bytes:
    html = build_invoice_html(customer_name, amount, items)
    return html_to_pdf(html, engine="quality", format="A4")


if __name__ == "__main__":
    pdf = generate_invoice_pdf(
        customer_name="株式会社サンプル",
        amount=150_000,
        items=[
            {"name": "Webシステム開発", "quantity": 1, "price": 120_000},
            {"name": "保守サポート(月額)", "quantity": 3, "price": 10_000},
        ],
    )
    with open("invoice.pdf", "wb") as f:
        f.write(pdf)
    print(f"請求書PDF生成: {len(pdf):,} bytes")

エラーハンドリングとリトライ

# pdf_client_production.py
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry


def create_pdf_session() -> requests.Session:
    """リトライ付きのHTTPセッションを作成する"""
    session = requests.Session()
    retry = Retry(
        total=3,
        backoff_factor=1.0,  # 1s, 2s, 4s でリトライ
        status_forcelist=[429, 500, 502, 503, 504],
        allowed_methods=["POST"],
    )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount("https://", adapter)
    return session


_session = create_pdf_session()


def html_to_pdf_with_retry(html: str, **kwargs) -> bytes:
    response = _session.post(
        f"{FUNBREW_API_URL}/pdf/from-html",
        headers={
            "Authorization": f"Bearer {FUNBREW_API_KEY}",
            "Content-Type": "application/json",
        },
        json={"html": html, "engine": "quality", "format": "A4", **kwargs},
        timeout=30,
    )
    response.raise_for_status()
    return response.content

2. ReportLab

インストール

pip install reportlab

基本的な使い方

# reportlab_basic.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Paragraph, Table, TableStyle, Spacer
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from io import BytesIO

# 日本語フォント登録(NotoSansCJKjp-Regular.otfが必要)
# pdfmetrics.registerFont(TTFont("NotoSans", "NotoSansCJKjp-Regular.otf"))


def generate_report_pdf(title: str, data: list[list]) -> bytes:
    """
    ReportLabで表形式レポートPDFを生成する。
    日本語を使う場合はフォント登録が必要。
    """
    buffer = BytesIO()
    doc = SimpleDocTemplate(
        buffer,
        pagesize=A4,
        topMargin=20 * mm,
        bottomMargin=20 * mm,
        leftMargin=15 * mm,
        rightMargin=15 * mm,
    )

    styles = getSampleStyleSheet()
    elements = []

    # タイトル
    elements.append(Paragraph(title, styles["Title"]))
    elements.append(Spacer(1, 12))

    # テーブル
    table = Table(data, colWidths=[80 * mm, 40 * mm, 40 * mm])
    table.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#2563eb")),
        ("TEXTCOLOR",  (0, 0), (-1, 0), colors.white),
        ("FONTSIZE",   (0, 0), (-1, 0), 11),
        ("ALIGN",      (1, 0), (-1, -1), "RIGHT"),
        ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#f1f5f9")]),
        ("GRID",       (0, 0), (-1, -1), 0.5, colors.HexColor("#e2e8f0")),
        ("TOPPADDING",    (0, 0), (-1, -1), 8),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 8),
    ]))
    elements.append(table)

    doc.build(elements)
    return buffer.getvalue()


if __name__ == "__main__":
    data = [
        ["商品名", "数量", "金額"],
        ["Product A", "10", "¥50,000"],
        ["Product B", "5",  "¥30,000"],
        ["Product C", "20", "¥80,000"],
    ]
    pdf = generate_report_pdf("売上レポート 2026年4月", data)
    with open("report_reportlab.pdf", "wb") as f:
        f.write(pdf)
    print(f"ReportLab PDF: {len(pdf):,} bytes")

ReportLabの特徴:

  • HTMLなしでプログラム的にPDFを組み立てる低水準API
  • 日本語にはフォント登録が必要(TTFont.otf.ttfを読み込む)
  • グラフ描画(reportlab.graphics)が得意
  • 複雑なHTMLレイアウトの再現は困難

3. WeasyPrint

インストール

# macOS
brew install python3 pango
pip install weasyprint

# Ubuntu/Debian
sudo apt-get install python3-cffi libcairo2 libpango-1.0-0 libgdk-pixbuf2.0-0
pip install weasyprint

基本的な使い方

# weasyprint_basic.py
from weasyprint import HTML, CSS
from io import BytesIO


def html_to_pdf_weasyprint(html: str, base_url: str | None = None) -> bytes:
    """WeasyPrintでHTMLをPDFに変換する"""
    buffer = BytesIO()
    HTML(string=html, base_url=base_url).write_pdf(
        buffer,
        stylesheets=[CSS(string="@page { size: A4; margin: 20mm 15mm; }")],
    )
    return buffer.getvalue()


html = """<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <style>
    body { font-family: sans-serif; padding: 20px; }
    h1 { color: #2563eb; border-bottom: 2px solid #2563eb; padding-bottom: 8px; }
    table { width: 100%; border-collapse: collapse; margin-top: 16px; }
    th { background: #dbeafe; padding: 8px; text-align: left; }
    td { padding: 8px; border-bottom: 1px solid #e2e8f0; }
  </style>
</head>
<body>
  <h1>WeasyPrint デモ</h1>
  <table>
    <thead><tr><th>項目</th><th>値</th></tr></thead>
    <tbody>
      <tr><td>ライブラリ</td><td>WeasyPrint 62.x</td></tr>
      <tr><td>エンジン</td><td>Cairo / Pango</td></tr>
      <tr><td>日本語対応</td><td>システムフォント使用</td></tr>
    </tbody>
  </table>
</body>
</html>"""

pdf = html_to_pdf_weasyprint(html)
with open("output_weasyprint.pdf", "wb") as f:
    f.write(pdf)
print(f"WeasyPrint PDF: {len(pdf):,} bytes")

WeasyPrintの特徴:

  • HTMLとCSSを比較的忠実に再現(CSS Paged Media対応)
  • GTK/Pangoへの依存があり、Dockerイメージが大きくなりやすい
  • JavaScript非対応(動的レンダリング不可)
  • 日本語はシステムフォントに依存(環境によってフォントが変わる)

4. xhtml2pdf

インストール

pip install xhtml2pdf

基本的な使い方

# xhtml2pdf_basic.py
from io import BytesIO
from xhtml2pdf import pisa


def html_to_pdf_xhtml2pdf(html: str) -> bytes:
    """xhtml2pdfでHTMLをPDFに変換する"""
    buffer = BytesIO()
    result = pisa.CreatePDF(html, dest=buffer)
    if result.err:
        raise RuntimeError(f"xhtml2pdf変換エラー: {result.err}")
    return buffer.getvalue()


html = """<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    @page { size: A4; margin: 20mm; }
    body { font-family: sans-serif; font-size: 12px; }
    h1 { color: #2563eb; }
  </style>
</head>
<body>
  <h1>xhtml2pdf サンプル</h1>
  <p>シンプルなPDFを手軽に生成できます。</p>
</body>
</html>"""

pdf = html_to_pdf_xhtml2pdf(html)
with open("output_xhtml2pdf.pdf", "wb") as f:
    f.write(pdf)
print(f"xhtml2pdf PDF: {len(pdf):,} bytes")

xhtml2pdfの特徴:

  • 外部バイナリ不要で軽量
  • CSS 2.1の一部のみ対応(Flexbox・Grid・CSS変数は非対応)
  • シンプルなレイアウトには十分だが複雑なデザインは崩れやすい
  • 日本語には別途フォント指定が必要

5. pdfkit(wkhtmltopdf)

インストール

# wkhtmltopdfバイナリが別途必要
# macOS: brew install wkhtmltopdf
# Ubuntu: sudo apt-get install wkhtmltopdf

pip install pdfkit

基本的な使い方

# pdfkit_basic.py
import pdfkit


options = {
    "page-size": "A4",
    "margin-top": "20mm",
    "margin-bottom": "20mm",
    "margin-left": "15mm",
    "margin-right": "15mm",
    "encoding": "UTF-8",
    "enable-local-file-access": "",
}

# HTML文字列からPDF生成
html = """<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>body{font-family:sans-serif;padding:40px;}</style>
</head>
<body>
  <h1 style="color:#2563eb">pdfkit サンプル</h1>
  <p>wkhtmltopdfを使ってPDFを生成します。</p>
</body>
</html>"""

# ファイルに保存
pdfkit.from_string(html, "output_pdfkit.pdf", options=options)

# バイナリとして取得
pdf_bytes = pdfkit.from_string(html, False, options=options)
print(f"pdfkit PDF: {len(pdf_bytes):,} bytes")

# URLからPDF生成
# pdfkit.from_url("https://example.com", "output_url.pdf")

pdfkitの特徴:

  • wkhtmltopdfバイナリが必須(サーバーへのインストールが必要)
  • CSS 3の多くをサポートするが、最新CSSには追従していない
  • wkhtmltopdfはメンテナンス停止状態(2024年以降更新なし)
  • 既存のwkhtmltopdf環境を維持する場合に有用

6. Playwright for Python

インストール

pip install playwright
playwright install chromium

基本的な使い方

# playwright_basic.py
import asyncio
from playwright.async_api import async_playwright


async def html_to_pdf_playwright(html: str, output_path: str = "output.pdf") -> bytes:
    """Playwright for PythonでHTMLをPDFに変換する(非同期)"""
    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_bytes = await page.pdf(
            format="A4",
            margin={"top": "20mm", "bottom": "20mm", "left": "15mm", "right": "15mm"},
            print_background=True,
        )
        await browser.close()
        return pdf_bytes


async def main():
    html = """<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <style>
    body { font-family: 'Noto Sans JP', sans-serif; padding: 40px; }
    h1 { color: #2563eb; }
    .chart-placeholder {
      width: 400px; height: 200px; background: #dbeafe;
      display: flex; align-items: center; justify-content: center;
      border-radius: 8px; font-size: 14px; color: #1e40af;
    }
  </style>
</head>
<body>
  <h1>Playwright PDF デモ</h1>
  <p>JavaScriptのレンダリング結果を含むPDFを生成できます。</p>
  <div class="chart-placeholder">グラフエリア(JS描画)</div>
</body>
</html>"""

    pdf = await html_to_pdf_playwright(html)
    with open("output_playwright.pdf", "wb") as f:
        f.write(pdf)
    print(f"Playwright PDF: {len(pdf):,} bytes")


asyncio.run(main())

Playwright for Pythonの特徴:

  • Chromiumを内蔵し、JavaScriptの実行結果も含めてPDFを生成できる
  • playwright install chromium で約200MBのバイナリが追加される
  • ローカル開発・テスト自動化と組み合わせる場合に特に有効
  • 本番環境ではFUNBREW PDF APIに移行するとインフラが軽くなる

ユースケース別の選び方

請求書・契約書(複雑なレイアウト、日本語あり)

推奨: FUNBREW PDF API

# ✅ HTMLとCSSを完全制御。日本語フォントも問題なし
pdf = html_to_pdf(invoice_html, engine="quality")

HTMLとCSSで既にデザインされた帳票テンプレートがある場合、PDF APIへのHTTPリクエスト1回で高品質なPDFを得られます。Django・FastAPIでのPDF API連携も参照してください。

データ分析レポート(グラフ・表のみ)

推奨: ReportLab

# ✅ matplotlibのグラフをReportLabに埋め込む
from reportlab.platypus import Image as RLImage
import matplotlib.pyplot as plt
from io import BytesIO

# matplotlibでグラフを生成
fig, ax = plt.subplots(figsize=(5, 3))
ax.bar(["Q1", "Q2", "Q3", "Q4"], [120, 145, 132, 178])
ax.set_title("四半期売上")
img_buffer = BytesIO()
fig.savefig(img_buffer, format="png", dpi=150, bbox_inches="tight")
img_buffer.seek(0)
plt.close(fig)

# ReportLabに埋め込む
chart_img = RLImage(img_buffer, width=130*mm, height=78*mm)
elements.append(chart_img)

大量バッチ生成(数百〜数千件)

推奨: FUNBREW PDF API + 非同期並列処理

# batch_pdf.py
import asyncio
import aiohttp
from typing import AsyncIterator


async def html_to_pdf_async(
    session: aiohttp.ClientSession,
    html: str,
    semaphore: asyncio.Semaphore,
) -> bytes:
    async with semaphore:
        async with session.post(
            f"{FUNBREW_API_URL}/pdf/from-html",
            headers={
                "Authorization": f"Bearer {FUNBREW_API_KEY}",
                "Content-Type": "application/json",
            },
            json={"html": html, "engine": "quality", "format": "A4"},
        ) as resp:
            resp.raise_for_status()
            return await resp.read()


async def generate_pdfs_batch(html_list: list[str], concurrency: int = 5) -> list[bytes]:
    """複数のHTMLを並列でPDF変換する"""
    semaphore = asyncio.Semaphore(concurrency)  # 同時5件に制限
    connector = aiohttp.TCPConnector(limit=10)

    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = [html_to_pdf_async(session, html, semaphore) for html in html_list]
        results = await asyncio.gather(*tasks, return_exceptions=True)

    # エラーを除外して成功分だけ返す
    pdfs = []
    for i, result in enumerate(results):
        if isinstance(result, Exception):
            print(f"[警告] {i}番目のPDF生成に失敗: {result}")
        else:
            pdfs.append(result)
    return pdfs


async def main():
    # 10件の請求書を並列生成
    html_list = [
        build_invoice_html(f"顧客{i:03d}", 100_000 + i * 5_000)
        for i in range(1, 11)
    ]
    pdfs = await generate_pdfs_batch(html_list, concurrency=5)
    print(f"{len(pdfs)}件のPDFを生成しました")


if __name__ == "__main__":
    asyncio.run(main())

詳細なバッチ処理のパターンはPDF一括生成ガイドを参照してください。

FastAPI・Django での組み込み

# FastAPI エンドポイント例
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel
from pdf_client import html_to_pdf

app = FastAPI()


class InvoiceRequest(BaseModel):
    customer_name: str
    amount: int
    items: list[dict] | None = None


@app.post("/api/pdf/invoice")
async def create_invoice_pdf(req: InvoiceRequest):
    try:
        html = build_invoice_html(req.customer_name, req.amount, req.items)
        pdf_bytes = html_to_pdf(html, engine="quality", format="A4")
        return Response(
            content=pdf_bytes,
            media_type="application/pdf",
            headers={
                "Content-Disposition": f"attachment; filename=invoice.pdf",
                "Content-Length": str(len(pdf_bytes)),
            },
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Django・Flask・FastAPIでの詳細な実装はDjango・FastAPI・FlaskでのPDF API統合ガイドで解説しています。

ライブラリ別 詳細比較

CSSサポート比較

CSS機能 FUNBREW PDF API WeasyPrint xhtml2pdf pdfkit
Flexbox
CSS Grid
CSS変数
@page ルール
WebFont(Google Fonts)
print-color-adjust

依存関係のサイズ比較

# FUNBREW PDF API
pip install requests  # ~2MB

# WeasyPrint
pip install weasyprint  # ~50MB(GTK含む)
# + brew install pango / apt-get install libpango-1.0-0

# pdfkit
pip install pdfkit  # ~1MB
# + wkhtmltopdf バイナリ ~90MB

# Playwright
pip install playwright  # ~15MB
playwright install chromium  # ~200MB

よくある質問

PythonでPDFを最も簡単に生成するには?

FUNBREW PDF APIを使う方法が最も簡単です。pip install requestsだけで始められ、複雑なHTMLのレイアウトやCSSもブラウザ品質で変換できます。外部バイナリのインストールが不要なため、Dockerイメージも軽量に保てます。

WeasyPrintをDockerで使うには?

GTK・Pango・Cairoなどの依存ライブラリをインストールする必要があります。Dockerfileに以下を追加してください:

FROM python:3.12-slim

RUN apt-get update && apt-get install -y \
    libpango-1.0-0 \
    libpangocairo-1.0-0 \
    libcairo2 \
    libgdk-pixbuf2.0-0 \
    libffi-dev \
    && rm -rf /var/lib/apt/lists/*

RUN pip install weasyprint

ただし、イメージサイズが増大するため、本番環境ではPDF APIへの切り替えを検討してください。

Pythonで日本語PDFが文字化けする場合は?

HTMLに<meta charset="UTF-8">を記述し、CSSでfont-family: 'Noto Sans JP', sans-serif;を指定してください。FUNBREW PDFはNoto Sans JPをプリインストール済みのため追加フォントは不要です。詳しくは日本語フォントガイドを参照してください。

ReportLabで日本語を使うには?

ReportLabはデフォルトで日本語フォントを持っていないため、.ttfまたは.otfファイルを登録する必要があります:

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

pdfmetrics.registerFont(TTFont("NotoSansJP", "/path/to/NotoSansCJKjp-Regular.otf"))
# 以降 fontName="NotoSansJP" で使用可能

pdfkitとWeasyPrint、どちらを選ぶべきか?

新規プロジェクトでは WeasyPrint を推奨します。pdfkitが依存するwkhtmltopdfは実質的にメンテナンスが停止しており、最新のCSSへの対応が不十分です。ただし、複雑なレイアウトや本番環境での安定性を重視するなら FUNBREW PDF API が最適です。

まとめ

PythonでのPDF生成手法をユースケース別にまとめます。

ユースケース 推奨手法 理由
請求書・証明書・帳票(HTMLデザインあり) FUNBREW PDF API 高品質・CSS完全対応・軽量
データ分析レポート(グラフ中心) ReportLab matplotlib連携・プログラム生成
既存HTMLアーカイブのPDF変換 WeasyPrint CSS Paged Media対応
シンプルな帳票(社内ツール) xhtml2pdf バイナリ不要・手軽
E2Eテストとの兼用 Playwright ブラウザ制御も同時にできる
大量バッチ生成・本番SaaS FUNBREW PDF API スケーラブル・インフラ不要

どのケースでも、まずプレイグラウンドでHTMLテンプレートを確認することをおすすめします。APIドキュメントでエンドポイントの詳細仕様も参照してください。

関連記事

Powered by FUNBREW PDF