1. 変換方式の全体像

PDF のページを PNG にする処理は、内部的には「PDF をレンダリング(描画)してラスタライズし、その結果を PNG として保存する」という流れです。実装の選択肢は大きく次の 2 系統に分かれます。

PDF を PNG に変換する処理フロー(PDF 入力→ページのレンダリング→ラスタライズ→PNG 出力)

系統 特徴 代表ライブラリ
自己完結型(外部ツール不要) pip / npm install だけで動く。導入が簡単 PyMuPDF(Python) / pdf-to-img(Node.js)
外部レンダラ依存型 Poppler や ImageMagick を別途インストール。高機能・高品質 pdf2image(Python) / pdf2pic(Node.js)

迷ったら自己完結型から始めると、環境構築でつまずきにくいです。以降で具体的なコードを示します。

2. Python での実装

2.1 PyMuPDF(推奨)

PyMuPDF は MuPDF をバックエンドに持つ高速な PDF ライブラリです。外部コマンドが不要で、インストールがシンプルです。

pip install pymupdf

各ページを PNG に書き出す最小コードは次のとおりです。

import pymupdf  # PyMuPDF

def pdf_to_png(pdf_path: str, dpi: int = 200) -> None:
    doc = pymupdf.open(pdf_path)
    try:
        for page in doc:  # ページを順番に処理
            pix = page.get_pixmap(dpi=dpi)  # 指定 DPI でレンダリング
            pix.save(f"page-{page.number + 1}.png")  # 1 始まりで保存
    finally:
        doc.close()

if __name__ == "__main__":
    pdf_to_png("input.pdf", dpi=200)

ポイントは次の 3 点です。

  • get_pixmap(dpi=...) で解像度を指定できます。デフォルトは 72 DPI(拡大率 1.0 の等倍。A4 ページは 595×842 ピクセルで出力される)なので、用途に応じて引き上げます。
  • dpi 引数で指定すると、生成された PNG ファイルに DPI 情報が埋め込まれるため、後工程(印刷・OCR)で扱いやすくなります。
  • 注釈(コメントやハイライト)を画像に含めたくない場合は page.get_pixmap(dpi=dpi, annots=False) を指定します。

dpi の代わりに倍率(ズーム)で指定したい場合は Matrix を使います。

zoom = 2.0  # 72 DPI の 2 倍 = 144 DPI 相当
mat = pymupdf.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=mat)

2.2 pdf2image(Poppler 利用)

pdf2image は Poppler の pdftoppm をラップしたライブラリです。Poppler の安定したレンダリングを使いたい場合に向いていますが、Poppler を別途インストールする必要があります。

# macOS
brew install poppler
# Ubuntu / Debian
sudo apt-get install poppler-utils

pip install pdf2image
from pdf2image import convert_from_path

def pdf_to_png(pdf_path: str, dpi: int = 200) -> None:
    pages = convert_from_path(pdf_path, dpi=dpi, fmt="png")
    for i, image in enumerate(pages, start=1):
        image.save(f"page-{i}.png", "PNG")

if __name__ == "__main__":
    pdf_to_png("input.pdf", dpi=200)

convert_from_path は各ページを Pillow の Image オブジェクトとして返すため、保存前にリサイズや切り抜きといった画像処理を挟めるのが利点です。ページ数の多い PDF でメモリが気になる場合は、first_page / last_page 引数で範囲を区切って処理します。

2.3 どちらを選ぶか

  • 依存を増やしたくない・速度重視 → PyMuPDF
  • すでに Poppler 環境がある・Pillow で後処理したい → pdf2image

なお PyMuPDF は AGPL / 商用デュアルライセンスです。商用プロダクトに組み込む場合はライセンス条件を確認してください。Poppler(pdf2image 経由)は GPL です。ライセンス要件が厳しい場合は、この点も選定基準になります。

3. Node.js での実装

3.1 pdf-to-img(推奨)

pdf-to-img は Mozilla の pdf.js をベースにした Pure JavaScript のライブラリで、ネイティブの外部ツールが不要です。Node.js 20 以降に対応しています。

npm install pdf-to-img

ESM(ES Modules)での最小コードは次のとおりです。

import { promises as fs } from "node:fs";
import { pdf } from "pdf-to-img";

async function main() {
  let counter = 1;
  // scale は解像度の倍率。高解像度が必要なら値を上げる
  const document = await pdf("input.pdf", { scale: 3 });
  for await (const image of document) {
    await fs.writeFile(`page-${counter}.png`, image);
    counter++;
  }
}

main();
  • scale オプションで解像度を調整します(デフォルトは 3)。各 image は PNG の Buffer として返ります。
  • 特定ページだけ欲しい場合は await document.getPage(12) のようにページ番号を指定して取得できます。
  • 暗号化された PDF は pdf("input.pdf", { password: "..." }) のようにパスワードを渡します。

CommonJS(require)環境では、動的 import() を使って読み込みます。

const { promises: fs } = require("node:fs");

async function main() {
  const { pdf } = await import("pdf-to-img");
  let counter = 1;
  const document = await pdf("input.pdf", { scale: 3 });
  for await (const image of document) {
    await fs.writeFile(`page-${counter}.png`, image);
    counter++;
  }
}

main();

3.2 pdf2pic(GraphicsMagick / ImageMagick 利用)

pdf2pic は GraphicsMagick と Ghostscript を利用してレンダリングします。高品質ですが、外部ツールの事前インストールが前提です。

# macOS
brew install graphicsmagick ghostscript
# Ubuntu / Debian
sudo apt-get install graphicsmagick ghostscript

npm install pdf2pic
import { fromPath } from "pdf2pic";

const convert = fromPath("input.pdf", {
  density: 200,        // DPI
  saveFilename: "page",
  savePath: "./output",
  format: "png",
  preserveAspectRatio: true,
});

async function main() {
  // -1 を渡すと全ページを一括変換
  const results = await convert.bulk(-1);
  console.log(`${results.length} ページを変換しました`);
}

main();

density が DPI に相当します。fromBuffer を使えば、ファイルではなくメモリ上の PDF バッファから変換することもできます。

3.3 どちらを選ぶか

  • 依存を増やしたくない・サーバーレスやコンテナで動かす → pdf-to-img
  • GraphicsMagick / Ghostscript が既にある・細かい画質制御をしたい → pdf2pic

サーバーレス環境やスリムな Docker イメージでは、ネイティブバイナリのインストールが負担になるため、pdf-to-img のような Pure JS 実装が扱いやすいです。

4. 解像度(DPI / scale)の決め方

PNG の品質はレンダリング解像度で決まります。用途別の目安は次のとおりです。

用途 目安
画面プレビュー・サムネイル 96〜150 DPI
一般的な閲覧・Web 表示 150〜200 DPI
印刷・OCR の前処理 200〜300 DPI
高精細な拡大表示 300 DPI 以上

注意点として、解像度を上げるほど 画像サイズとメモリ使用量がほぼ二乗で増加します。たとえば DPI を 2 倍にすると、ピクセル数は約 4 倍、ファイルサイズも増える傾向にあります(内容や圧縮率に依存します)。バッチ処理で多数の PDF を扱う場合は、必要十分な解像度に抑えるとリソースを節約できます。

pdf-to-img の scale は「72 DPI 基準の倍率」に近い概念です。scale: 3 はおおよそ 216 DPI 相当になります。

5. よくあるエラーと対処

  • PyMuPDF の import fitz が見つからない: 新しいバージョンでは import pymupdf が推奨されます(import fitz も後方互換で動作します)。
  • pdf2image で PDFInfoNotInstalledError: Poppler がインストールされていないか、PATH が通っていません。pdftoppm -v でインストールを確認してください。
  • pdf2pic で gm/convert: command not found: GraphicsMagick または Ghostscript が未インストールです。前述のコマンドで導入します。
  • pdf-to-img で import できない: 本ライブラリは ESM です。CommonJS では 3.2 節のように動的 import() を使ってください。
  • メモリ不足でクラッシュする: 全ページを一度に保持せず、ページごとにストリーム処理するか、DPI を下げて再試行します。

6. まとめ

PDF の各ページを PNG に変換するなら、まずは 依存の少ない自己完結型ライブラリから始めるのが近道です。

  • Python: PyMuPDFpip install pymupdf だけで完結。get_pixmap(dpi=...) で 1 ページずつ保存)
  • Node.js: pdf-to-img(Pure JS で外部ツール不要。scale で解像度を調整)

外部レンダラに依存する pdf2image / pdf2pic は、既存環境やライセンス要件にマッチする場合に選ぶとよいでしょう。解像度は用途に合わせて DPI を設定し、リソースと品質のバランスを取るのがポイントです。

参考リンク