weasyprintでMarkdownから紙品質のPDFを作る(連載⑰)

,

weasyprintでMarkdownから紙品質のPDFを作る(連載⑰)

weasyprintでMarkdownから紙品質のPDFを作る(連載⑰)

連載第17回です。前回は原稿の数値裏取りについて書きました。今回は、EPUBとは別ルートで用意しているPDF版の作り方です。連載第7回の最後で少し触れましたが、今回はweasyprintでのPDFビルドを掘り下げます。


PDF版が欲しくなる場面

Kindle本はEPUB(リフロー型)を主軸にしていますが、次のような場面ではPDFが別途必要になりました。

  • 校正時:印刷して赤入れする、あるいはタブレットに固定レイアウトで表示して通し読みする
  • 献本・共有:Kindleアプリを持っていない相手に原稿を見てもらう
  • 紙のような版面確認:図表の配置がリフロー型では崩れやすいため、固定レイアウトでの見え方を確認したい

EPUBはリフロー型ゆえに「今どのページを開いても文字サイズ・改行位置が変わりうる」構造です。校正や共有の場面では、むしろページが固定される紙に近い版面のほうが都合が良いことが多く、PDF版を別ビルドとして用意することにしました。


EPUB経由PDFの限界

最初はEPUBファイルをKindle Previewer や他の変換ツールでPDF化する方法も試しました。しかしEPUB自体がリフロー型を前提にしているため、変換後のPDFは次のような崩れが目立ちました。

  • 見開きページの概念がなく、余白の取り方が不自然
  • 画像の配置がCSSのリフロー指定に引きずられ、意図した位置からずれる
  • ページ番号・柱(ヘッダー/フッター)が入らない、または簡素すぎる

「リフロー用に作ったCSSを、固定レイアウトのPDFにそのまま流用する」こと自体に無理があると判断し、Markdown原稿から直接PDFを生成する別ビルドに切り替えました。


pandoc + weasyprint のコマンド

連載第7回で紹介したEPUBビルドと同じ原稿・同じmanuscript/フォルダから、次のコマンドでPDFを生成します。

cd manuscript
pandoc metadata.yaml [0-9]*.md \
  -o ../build/geodetic-book.pdf \
  --pdf-engine=weasyprint \
  --css=style.css --css=print.css \
  --toc --toc-depth=2

EPUB用のstyle.cssはそのまま読み込みつつ、PDF専用のprint.cssを追加で読み込む構成です。同じMarkdown原稿から、--pdf-engineの指定と追加CSSだけでEPUB/PDFの2形式を出し分けられるのは、Markdown一本化の実利をもっとも感じた部分です。


print.cssの要点

print.cssで調整しているのは、主に次の5点です。

項目 指定内容 狙い
ページサイズ @page { size: A4; margin: 20mm 18mm; } 印刷を想定した実寸のA4・余白
CJKフォント font-family にゴシック体・明朝体を明示指定 環境依存でCJKグリフが欠けるのを防ぐ
章の改ページ h1 { page-break-before: always; } 章の先頭を必ずページ先頭に揃える
図表の改ページ回避 figure { page-break-inside: avoid; } 表や図が2ページにまたがって分断されるのを防ぐ
縦長画像の高さ制限 img.tall { max-height: 88vh; } 縦長スクリーンショットが1ページに収まりきらず次ページへあふれるのを防ぐ

とくに縦長画像の扱いは、リフロー型Kindle本の図版設計(連載⑨)で書いた「本文図は横長で作る」という原則と表裏の関係にあります。横長図はリフロー型でも固定レイアウトでも比較的安全ですが、縦長のスマホスクリーンショットをPDFにそのまま置くとページからあふれるため、max-height: 88vhで明示的に上限を設けています。


ハマった罠:Homebrew版Pythonへの切替

weasyprintはPython製のライブラリで、依存するPangoやCairoなどのネイティブライブラリを必要とします。当初システム標準のPython環境でインストールしたところ、これらのネイティブライブラリのパス解決に失敗し、実行時にOSErrorでフォントが見つからないというエラーが頻発しました。

最終的に、Homebrewでインストールしたpython3と、Homebrew管理下のPango/Cairoを使う構成に切り替えることで解消しました。具体的には以下の対応です。

  • brew install weasyprint(Homebrewのformulaを利用し、ネイティブ依存を一括管理)
  • 仮想環境を作る場合も、Homebrew版python3をベースにvenvを作成する
  • DYLD_LIBRARY_PATHなどの環境変数に頼らず、Homebrewが管理するライブラリパスをそのまま使う構成にする

「pipでweasyprintだけ入れれば動く」と思い込んでいたのが原因で、ネイティブ依存を含むPythonパッケージは、パッケージマネージャ側での依存解決に素直に乗ったほうが結局早い、という教訓になりました。


同一原稿からのEPUB/PDF比較

同じ原稿・同じ図版から生成したEPUBとPDFを並べると、リフロー型と固定レイアウトの違いが分かりやすく確認できます。参考として、EPUBビルドパイプラインのイメージを再掲します。

pandocでMarkdownからEPUBを作る(連載⑦)のイメージ

EPUB版は文字サイズ変更に追従する代わりにページの概念が薄く、PDF版はページが固定される代わりに端末の文字サイズ設定を無視します。校正時はPDF、配布・販売はEPUBという使い分けに落ち着いています。


まとめ

  • EPUB経由のPDF変換はリフロー前提のCSSが崩れの原因になるため、Markdown原稿から直接PDFを生成する別ビルドに切り替えた。
  • pandoc --pdf-engine=weasyprintに専用のprint.cssを追加するだけで、同じ原稿からEPUBとPDFを出し分けられる。
  • print.cssではA4・余白・CJKフォント・章の改ページ・図表の改ページ回避・縦長画像の高さ制限(max-height: 88vh)の5点を調整している。
  • weasyprintはネイティブ依存が絡むため、pipではなくHomebrewでの依存管理に切り替えて安定させた。

次回は、本とnote連載を組み合わせた二段構えのプロモーション設計について書く予定です。

関連記事


開発者より: アプリ・Kindle本・オープンソースの一覧は GitHub: amru195704 にまとめています。


お願い
本記事の情報は参考目的で掲載しており、正確性・完全性を保証するものではありません。誤記・不正確な情報がございましたら、コメント欄よりご指摘いただければ、確認のうえ修正いたします。


アプリを入手(App Store)GeoConverterPro(座標変換) | GeoPrism JP(測地系の可視化・学習)


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

Back to top