Table of Contents
はじめに
小学生の娘が算数で間違った問題を、スキャンしてまとめてPDF化しています。しかし、必要なページだけ印刷したつもりが、結構ページ番号がずれていて、何度もやりなおしたりしています。電子化したつもりが意外とアナログです。そこで、自動でPDFファイルにページ番号を付けたいと思いました。ヒューマンエラーによるページ番号のずれが防げる、またはずれてもすぐに気がつくので。
しかし、PDFにページ番号を付けたいという単純なことなのに、意外にも良い実現方法が見つかりません。検索した結果、いくつかWebサービスを見つけて試してみましたが、あるものはページを入れる位置が気に入らない、またあるものは、たくさんページ番号を付けていると有料になる(しかも月極subscription)などでした。
そこで、最近使えるようになって気を良くしているPythonで、PDFにページ番号が付けられないか調べてみたのですが、このユースケースに対応するPDFライブラリは無さそう(少なくとも単体では)、ということがわかりました。
この記事は https://achiwa912.github.io/ にも載せました。
ReportLab PDFライブラリ
PythonでのPDFライブラリで有名なものは、PyPDF2, pdfrwあたりのようです。これらは、複数のPDFファイルをマージしたり、逆に分割したり、ページを入れ替えたりといったことが得意ですが、「既存PDFファイルにページ番号を付加する」というユースケースには対応していないようです。
更に調べてみると、どうやらReportLabライブラリでページ番号を付けられそうだ、ということがわかりました。
https://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/
このWebページはとても期待させるタイトルなのですが、サンプルコードを見てみると疑問がわいてきます。そもそも、既存PDFファイルを読み込んでおらず、新規に作成したPDFのページにページ番号を付与しているようです。駄目じゃん。。。
マニュアルにも一通り目を通してみます。
https://www.reportlab.com/docs/reportlab-userguide.pdf
ここでも、既存PDFファイルを読み込む説明はありませんでした。
ReportLab + pdfrwを組み合わせる
それでも諦めずに検索を続けたところ、見つけました。
https://stackoverflow.com/questions/28281108/reportlab-how-to-add-a-footer-to-a-pdf-file
さすがstackoverflow! 日本のqiitaと並んで大好きです。
どうやら、ReportLabとpdfrwを組み合わせるとできそうなことが書いてあります。
気になる記述もありますが。。。
DISCLAIMER: Tested on Linux using as input file a pdf file generated by Reportlab. It would probably not work in an arbitrary pdf file.
「ReportLabで作成したPDFファイルでテストしたけど、任意のPDFファイルだと動かないんじゃないかな」
・・・えー!! でもこれしか頼れる物がありません。試してみましょう。
stakoverflowのページに載っているサンプルコードを改変してみます。
from reportlab.pdfgen.canvas import Canvas
from pdfrw import PdfReader
from pdfrw.toreportlab import makerl
from pdfrw.buildxobj import pagexobj
import sys
import os
if len(sys.argv) != 2 or ".pdf" not in sys.argv[1].lower():
print(f"Usage: python {sys.argv[0]} <pdf filename>")
sys.exit()
input_file = sys.argv[1]
output_file = os.path.splitext(sys.argv[1])[0] + "_pgn.pdf"
reader = PdfReader(input_file)
pages = [pagexobj(p) for p in reader.pages]
canvas = Canvas(output_file)
for page_num, page in enumerate(pages, start=1):
canvas.doForm(makerl(canvas, page))
footer_text = f"{page_num}/{len(pages)}"
canvas.saveState()
canvas.setStrokeColorRGB(0, 0, 0)
canvas.setFont('Times-Roman', 14)
canvas.drawString(290, 10, footer_text)
canvas.restoreState()
canvas.showPage()
canvas.save()
そして実行すると、、、、
あれ、さくっと動いてしまいました。念のため、ページの下に書いてある7/88というところが、今回入れたページ番号です。あのdisclaimerは何だったのか。。。
使用方法
f-stringを使っているので、python 3.6以降で使ってください。
PDFライブラリインストール
pip install reportlab
pip install pdfrw
上記コードをaddpagenum.pyとしてセーブ。(ファイル名は好きに変えてください)
実行
python addpagenum.py <pdf_filename>
ページ番号はA4でページ中央下に表示します。
カスタマイズ方法
このあたりを適当に変えてください。
footer_text = f"{page_num}/{len(pages)}"
canvas.setFont('Times-Roman', 14)
canvas.drawString(290, 10, footer_text)
- 表示内容を変える場合はfooter_textを変える
- ページ番号表示位置を変えたい場合は、x=290, y=10を変える
なお、ReportLabのcanvasにおいて、座標の(x=0, y=0)はページ左下になっています。
A4以外のLetter等にしたい場合は、canvasオブジェクトを作成する際に指定します。
詳しくはReportLabマニュアルを参照してください。