
このPDF を Docling https://www.docling.ai/ を使って markdown に変換してみます。
ここでは M1 Macbook Air を使っています。
Docling を使うには:
pip install docling
これだけで使えるのですが、 (この環境では) homebrew でインストールしている Python 3.13.2 ではうまく動きませんでした。 macOS (Sonoma 14.7.5) 標準の /usr/bin/python3 (Python 3.9.6) を使えば問題ない。 次のようにして venv 環境で Docling を試すとよい:
/usr/bin/python3 -m venv .venv
source .venv/bin/activate
PDF から markdown に変換するには:
docling ./pokemon_doc.pdf
結果は ./pokemon_doc.md に保存されます。
直接ネット上のPDFを指して実行もできる:
docling https://blog.mindboardapps.com/posts/pdf-to-markdown-with-docling/images/pokemon_doc.pdf
オプションを指定しないと 画像部分が base64 文字列に変換され出力する markdown ファイルに埋め込まれます。 これはこれで便利なのですが、
とか
を使うこともできます。
docling ./pokemon_doc.pdf --image-export-mode placeholder
この場合は画像は次のようなプレースホルダー文字列で置き換えられた:
<!-- image -->
docling ./pokemon_doc.pdf --image-export-mode referenced
この場合は画像は次のようなプレースホルダー文字列で置き換えられた:

なお表組部分は次のようにマークダウンのテーブル形式に変換される:
## 表1. 御三家ポケモン⼀覧
| No. | 画像 | ⽇本語名 | 英語名 | タイプ | 世 代 | HP |
|-------|--------------|--------|----------|---------|-------|------|
| 001 | treecko.png | キモリ | Treecko | くさ | 第3 | 40 |
| 002 | torchic.png | アチャモ | Torchic | ほのお | 第3 | 45 |
| 003 | mudkip.png | ミズゴロ ウ | Mudkip | みず | 第3 | 50 |
| 004 | turtwig.png | ナエトル | Turtwig | くさ | 第4 | 55 |
| 005 | chimchar.png | ヒコザル | Chimchar | ほのお | 第4 | 44 |
| 006 | piplup.png | ポッチャ マ | Piplup | みず | 第4 | 53 |
| 007 | rowlet.png | モクロー | Rowlet | くさ・ひこ う | 第7 | 68 |
| 008 | litten.png | ニャビー | Litten | ほのお | 第7 | 45 |
| 009 | popplio.png | アシマリ | Popplio | みず | 第7 | 50 |
次のように直接 python コードを記述すれば、画像や表組の処理を自前のコードで差し替えることができる。
標準の画像処理 MarkdownPictureSerializer を継承して自前処理にした MyPictureSerializer :
class MyPictureSerializer(MarkdownPictureSerializer):
def __init__(self, output_dir, doc_stem):
super().__init__()
self.output_dir = output_dir
self.doc_stem = doc_stem
self.counter = 0
def serialize(self, *, item, doc_serializer, doc, **kwargs):
self.counter += 1
filename = f"{self.doc_stem}-picture-{self.counter}.png"
item.get_image(doc).save(self.output_dir / filename, format="PNG")
return SerializationResult(text=f"")
標準の表組処理 MarkdownTableSerializer を継承して自前処理にした MyTableSerializer :
class MyTableSerializer(MarkdownTableSerializer):
def __init__(self, output_dir, doc_stem):
super().__init__()
self.output_dir = output_dir
self.doc_stem = doc_stem
self.counter = 0
def serialize(self, *, item, doc_serializer, doc, **kwargs):
self.counter += 1
img = item.get_image(doc)
if img is None:
return super().serialize(item=item, doc_serializer=doc_serializer, doc=doc, **kwargs)
filename = f"{self.doc_stem}-table-{self.counter}.png"
img.save(self.output_dir / filename, format="PNG")
return SerializationResult(text=f"")
このカスタマイズでは、該当部分を画像ファイルとして書き出すと同時に画像をリンクする markdown 記述を出力している。
このコード:
img = item.get_image(doc)で該当領域が画像として取り出せるので、これを API 経由で AIに渡して何かする...
- 画像のキャプション(説明)を生成してそれを markdown として出力する
- 表組を CSV や JSON に変換してそれを markdown 出力する
などのカスタマイズが可能になる。
もちろん、 これらの自前シリアライザーを使ってPDF文書全体をマークダウン変換するため MarkdownDocSerializer をカスタマイズする必要あり:
def to_markdown(converter, input_path, output_dir, doc_stem):
doc = converter.convert(str(input_path)).document
serializer = MarkdownDocSerializer(
doc=doc,
picture_serializer=MyPictureSerializer(output_dir, doc_stem),
table_serializer=MyTableSerializer(output_dir, doc_stem),
params=MarkdownParams(image_placeholder="", image_mode=ImageRefMode.PLACEHOLDER),
)
return serializer.serialize().text
MarkdownDocSerializer で picture_serializer, table_serializer を自前のそれに差し替える。
画像や表組を実際に画像として出力する場合は PdfPipelineOptions で generate_picture_images とか generate_table_images を True に指定する必要がある・・・など、いろいろハマりどころはある。
pipeline_options = PdfPipelineOptions(
enable_remote_services=False,
do_picture_description=False,
generate_picture_images=True,
images_scale=2.0,
do_table_structure=True,
generate_table_images=True,
)
Docling の入力は PDF 以外にも DOCX, PPTX なども使える。 ただし、DOCX や PPTX を入力した場合、PDF と異なる処理方法がたぶん使われる(詳細はドキュメントで確認のこと)。 PDF 入力の場合に関しては、 テキスト取り出し処理が行われる前にまずページ全体のレイアウトを AI が判定、 人間にとって自然な順でテキスト取り出しができる。 これが Docling を使う利点の一つ。 もう一つの利点は、ここで説明したように、ドキュメント中の 画像 / 表組 を認識して、それぞれそれ用の処理を使って変換されること。 そしてこの処理を自前のものに差し替えることができる。
なお、画像 / 表組 識別以外に 見出し / 段落 / リスト / コード / 数式 なども識別するようです。 Docling の Features を参照。
それぞれに シリアライザーがありカスタマイズ可能かどうかは調べていません。
本文テキストの取り出し処理は LLM OCR など AI を使っているわけではなく従来方式で PDF から普通にテキスト取り出ししているだけなのでハルシネーションの心配はない(と思う)。 また、 AI 処理を挟むといっても Docling にビルトインされている AI 処理範囲であれば M1 Macbook Air 8GB の非力なマシンでも普通に使える。 大量のドキュメントを頻繁に処理する場合などはまた話は別かもしれない。