1001001

73。CTFのWrite-upや技術的な備忘録を書きとめたいです。

【pypdf】片面ずつスキャンしたPDFを結合して両面スキャンしたかのようにしたい

はじめに

pypdfで2つのPDFファイルを1ページずつ交互に連結する方法と,PythonでのPDF操作のライブラリに関して調べたことの備忘録です.

問題

長辺閉じのA4資料を両面スキャンしたかったのだが、自宅のBrother製プリンターが対応していなかった.仕方ないので片面ずつスキャンした2つのPDFを後から処理して,ページの整合性を保ちつつ,一つのPDFにしたい.
(1枚ずつ手作業で表裏返しながらならできるのですが,紙送りモードでは非対応)

解決方法

pypdfを使って,2つのPDFの各頁を交互にくっつけるスクリプトを書いた.スキャンの順序の関係で,以下のスクリプトでは表PDFの最初1ページ目と,裏PDFの後ろ最後1ページ目から交互に結合している。

詳細は参考に載せているドキュメントのMerging PDF Files辺りを見るのがわかりやすい.

from pypdf import PdfReader, PdfWriter

def main():
    reader1 = PdfReader("omote.pdf") # 表面
    reader2 = PdfReader("ura.pdf") # 裏面
    number_of_pages1 = len(reader1.pages)
    number_of_pages2 = len(reader2.pages)

    # 最後のページが白紙だろうと気にせずスキャンしたので,
    # 表面PDFと裏面PDFの枚数は同じになる.ページ数同じ想定で進むのでそうでなければ念の為止める
    assert number_of_pages1 == number_of_pages2

    writer = PdfWriter() # PdfWriterでmergeやappendができる(appendは最後に追加,mergeはposition指定できる)
    for i in range(number_of_pages1): # 単純に,表面PDFは1枚目から,裏面PDFは最終ページから順に取って並べていく
        # fileobjはpdf名を指定して作成したPdfReaderオブジェクトを指定する
        # pagesは,(start, stop[, step]) で範囲指定するので,今回は1頁ずつ取ってくるようにする
        writer.append(fileobj=reader1, pages=(i, i+1))
        writer.append(fileobj=reader2, pages=(number_of_pages2-i-1, number_of_pages2-i)) 

    with open("test.pdf", "wb") as f:
        writer.write(f)

if __name__ == "__main__":
    main()

Pythonでpdf操作するライブラリって他にあるの?

pypdfはforkがめちゃくちゃいっぱいあって,pypdf2,pypdf3,pypdf4などあるが,pypdfを使っておけば良いらしい.
www.reddit.com

  • pypdf2は良いforkで最近pypdfに統合された
  • pypdf3,4は良くないfork(何が良くないのかは書いていない)
  • 要するにpypdfを使えば良い

といったことが書いてある.
あと,どうやらテキスト操作とか必要ならPyMuPDFというのも選択肢に入ってくるらしい.

以下の記事でも,pypdf使うといいよ〜って書いてあった。
qiita.com

他に解決方法ないの?

VB.NETC#で同じようなことをやっているものがあった。今回環境がMacだったのでPythonの方が楽だと思いpypdfにした。
https://support.mescius.jp/hc/ja/articles/360004021355-複数のPDFを1ページずつ交互に結合する方法