PDF 切り離しで画像とテキストを簡単抽出する手順

PDFから画像とテキストを「切り離し」て抽出したい――そんなニーズはデータ解析・リサーチ・コンテンツ制作の現場でよく聞かれます。
ここでは、コマンドラインツールPythonライブラリを併用した実践的な手順を紹介します。
「どんな形式のPDFでも扱える」「画像は高画質で取得できる」「テキストは検索可能なテキストとして出力できる」ことを目指しています。

1. PDFの構造を理解しておく

PDFは「ページ」「オブジェクト」「エンティティ」という階層構造を持ちます。

  • テキスト文字オブジェクトとしてPDF内に格納され、フォント情報と位置情報が紐づいています。
  • 画像イメージオブジェクトとしてストリームに埋め込まれるため、JPEG・PNG・JBIG2等の圧縮形式が混在します。

これらが混在したページから目的の要素だけを抜き出すには、
① 画像抽出ツール② テキスト抽出ツールが必要になります。
また、スキャンド(画像だけのPDF)ではOCRが必須です。

2. 画像だけを抜き出す方法

2‑1 poppler-utils (pdfimages)

# Debian/Ubuntu など
sudo apt-get install poppler-utils

# 画像をJPEG(もしくはPNG)で抽出
pdfimages -j input.pdf img_prefix
  • -j で圧縮ストリームをそのままJPEG出力します。
  • 出力ファイルは img_prefix-000.jpg, img_prefix-001.jpg のように連番で保存されます。
  • PNG画像はそのままPNGで抽出出来ます(拡張子は.png)。

2‑2 MuPDF (mutool)

sudo apt-get install mupdf-tools
mutool extract input.pdf
  • extract は PDF に含まれる すべてのオブジェクト(画像・テキスト・フォントなど)をディレクトリごとに分離します。
  • 画像は image/ フォルダに保存され、画像の形式はそのまま出力されます。

2‑3 ImageMagick (convert)

sudo apt-get install imagemagick
convert -density 300 input.pdf page-%d.png
  • -density 300 で高解像度(300dpi)に設定。
  • それぞれのページを PNG 画像として保存します。
  • ただし「画像としての出力」なので、テキストも画像状態で保存されます。

3. テキストだけを抜き出す方法

3‑1 pdftotext (poppler-utils)

sudo apt-get install poppler-utils
pdftotext -layout input.pdf output.txt
  • -layout でレイアウトを保持し、段組みをなるべく正確に再現します。
  • フォントが埋め込み済みであれば、文字コードは UTF‑8 で生成されます。

3‑2 pdfplumber (Python)

import pdfplumber

with pdfplumber.open("input.pdf") as pdf:
    all_text = ""
    for page in pdf.pages:
        all_text += page.extract_text() + "\n\n"
    with open("output.txt", "w", encoding="utf-8") as f:
        f.write(all_text)
  • extract_text() は PDF 内の文字列を位置情報に基づいて結合します。
  • テーブルも抽出可能です(page.extract_table())。

3‑3 pdfminer.six (Python)

from pdfminer.high_level import extract_text

text = extract_text("input.pdf")
with open("output.txt", "w", encoding="utf-8") as f:
    f.write(text)
  • pdfminer はレイアウト解析に優れ、テキストと画像を明確に区別します。

4. OCR 必須のスキャンド PDF に対して

スキャンド PDF はテキストが画像として埋め込まれているため、OCR(光学式文字認識) が必要です。
おすすめは Tesseractpdf2image の組み合わせです。

# 1. 画像化
sudo apt-get install poppler-utils
pdfimages -png input.pdf page

# 2. OCR 実行
tesseract page-000.png output -l jpn pdf
  • pdf2image を使えば直接 PDF → PIL Image → OCR の流れを作れます。
from pdf2image import convert_from_path
import pytesseract

pages = convert_from_path('input.pdf', dpi=300)
for i, page in enumerate(pages):
    text = pytesseract.image_to_string(page, lang='jpn')
    with open(f"ocr_page_{i+1}.txt", "w", encoding="utf-8") as f:
        f.write(text)

4‑1 OCR 効率化のヒント

機能 補足
言語設定 lang='jpn' で日本語を優先。複数言語なら lang='jpn-vert+jpn' で縦書きも扱える。
事前画像処理 pytesseract.image_to_string の前に PIL で convert('L')(グレースケール)や ImageOps.invert() でコントラストを調整すると精度上がる。
Tesseract のデータ tesseract-ocr-jpn の拡張パックを入れると、漢字認識が大幅向上。

5. 画像とテキストを分離した後の仕上げ

  1. 画像の品質確認

    • pdfimages で抽出した JPEG はそのまま高画質です。必要に応じて jpegoptim で圧縮率調整。
    • PNG は optipngpngquant で軽量化可能。
  2. テキストの整形

    • pdftotext -layout で段落や改行が乱れがち。
    • sed で連続空白を一つに、空行を減らすなどのテキストクレンジングが有効です。
sed -e 's/  */ /g' -e '/^$/d' raw.txt > clean.txt
  1. ファイル統合

    • 取得した PNG と TXT を同じフォルダに保管し、ファイル名にページ番号を付与すれば管理が楽。
    • さらに Markdown 形式に変換し、画像として埋め込む例:
    # ページ1
    ![](img/page-000.png)
    
    ## テキスト
    {はじめに text-from-page-1.txt}
    
  2. Git でバージョン管理

    • 大量の画像は Git LFS(Large File Storage)に格納し、テキストとメタデータだけを Git で管理。

6. コマンドラインワンライナーで全自動化

#!/usr/bin/env bash
# 画像・テキスト抽出を一括実行するスクリプト
INPUT="input.pdf"
mkdir -p out/img out/text

# 画像抽出
pdfimages -j "$INPUT" out/img/img

# テキスト抽出
pdftotext -layout "$INPUT" out/text/raw.txt

# OCR を必要とするか判定(簡易版)
if grep -qP '\x{FF00}' out/text/raw.txt; then
  echo "OCR required"
  for i in out/img/img-*; do
    png2pdf "$i" | tesseract stdin - -l jpn pdf
  done
fi
  • このスクリプトを cron で定時実行すれば、定期的に PDF をアップロードして自動でデータ化できます。

7. よくあるトラブルと対策

トラブル 原因 対策
画像が全ページに抽出される pdfimages は PDF 内のすべてのイメージオブジェクトを返すため、白紙ページにも画像があるように見える pdfimages -p でページ番号を付与、フィルタで白画素割合が高い画像を除外
テキストが途中で途切れる PDF に埋め込まれたフォントが欠落している Adobe Acrobat の「テキスト認識」 -> "フォントを埋め込む" を実行
OCR の文字化け 日本語語彙が不足 tesseract --oem 1 --psm 3 -l jpn で OCR エンジンを LSTM に変更、--user-words で辞書を補完
PDF がパスワードで保護されている poppler の pdftotext-upw でユーザパスワード指定可能 pdftotext -upw "password" input.pdf output.txt

8. まとめ

  • 画像の取得pdfimages が最も簡単で高画質。
  • テキストの取得pdftotext(レイアウト維持)と pdfplumber(Python API)を併用。
  • スキャンド PDFOCR(Tesseract + pdf2image)を必ず通す。
  • スクリプトでワンライナー化すれば、毎回同じ手順をループする必要は無い。
  • 大量データの場合は Git LFS で画像管理、Makefile でタスクを整理すると作業効率が飛躍的に上がります。

これらを組み合わせることで、PDF 内の 画像テキスト を「切り離し」て簡単に抽出・再利用できる環境を構築できます。ぜひご自身のプロジェクトに合わせてカスタマイズしてみてください。

コメント