LoginSignup
5
6

More than 1 year has passed since last update.

【Python】単ページのPDFを見開きで結合する方法

Posted at

概要

pypdfを使い、下図のような単ページのPDFを見開きで結合する方法を紹介します。
image.png

各種インポート

インストール
pip install pypdf
各種インポート
from pypdf import PdfWriter, PdfReader, PageObject, Transformation

実行時の各種バージョン

Name Version
pypdf 3.2.0

注意
pypdf 3.0.0以降のバージョンで、pypdfの変数名などが大幅に変更されているので注意してください。本記事は、pypdf 3.0.0以降で機能します。
(参考:https://github.com/py-pdf/pypdf/commit/a4629d3dbdef2759ff6059446fcffd13ecf6a396)

サンプルファイル

サンプルで使用したPDFファイルです。よろしければシミュレーションとしてお使いください。

実装コード

Google Colabで作成したコードは、こちらにあります。

方法

from pypdf import PdfWriter, PdfReader, PageObject, Transformation


infile = './sample.pdf'  # 単ページのPDF
outfile = './sample_merge_2page.pdf'  # 見開きのPDFの保存ファイル

reader = PdfReader(infile)
writer = PdfWriter()

for i in range(0, len(reader.pages), 2):
    p1 = reader.pages[i]
    if i+1 == len(reader.pages):  # ページ総数が奇数の場合に、右ページに空白を補完
        p2 = PageObject.create_blank_page(width=p1.mediabox.right, height=p1.mediabox.top)
    else:
        p2 = reader.pages[i+1]
    width_1_2 = p1.mediabox.right + p2.mediabox.right
    height_1_2 = max(p1.mediabox.top, p2.mediabox.top)
    p_1_2 = PageObject.create_blank_page(width=width_1_2, height=height_1_2)

    # 見開きにするため、右ページ用のPDFを右に平行移動、mediaboxもそれに合わせて右に平行移動
    op = Transformation().translate(tx=p1.mediabox.right)
    p2.add_transformation(op)
    p2.mediabox.left = p1.mediabox.right
    p2.mediabox.right = p1.mediabox.right + p2.mediabox.right

    p_1_2.merge_page(p1)
    p_1_2.merge_page(p2)
    writer.add_page(p_1_2)

with open(outfile, mode='wb') as f:
    writer.write(f)

コードの説明

  1. 見開きページなので左ページと右ページを2つ同時に読み込むので、range(0, len(reader.pages), 2)とし、iに左ページのindexを渡します。
  2. p1 = reader.pages[i]で、p1に左ページ用の単ページのpdfを読み込みます。
  3. if文はページの総数が奇数の場合のみ、最終ページの右ページに左ページと同じサイズの余白PageObject.create_blank_page(width=p1.mediabox.right, height=p1.mediabox.top)を追加するため、読み込みます。
  4. p2 = reader.pages[i+1]で、p2に右ページ用の単ページのpdfを読み込みます。
  5. width_1_2で、見開きページの横サイズを計算します。
  6. height_1_2で、見開きページの縦サイズを計算します。(max()を使うことで、左右のページの縦サイズが異なる場合に、縦サイズの大きい方に合わせたサイズにすることができます。)
  7. p_1_2 = PageObject.create_blank_page(width=width_1_2, height=height_1_2)で、見開きの空白ページを作ります。この空白ページに右ページと左ページを結合していきます。
  8. 見開きにしたいので、op = Transformation().translate(tx=p1.mediabox.right)で、右にp1.mediabox.rightだけ平行行移動する変換変数opを用意します。
  9. p2.add_transformation(op)で、p2を右にp1.mediabox.rightだけ平行移動させます。
  10. add_transformation()は、mediabox(表示領域)の情報がそのまま維持されてしまうので、mediaboxも右に同じだけ平行移動させるために、p2.mediabox.left, p2.mediabox.rightを調整します。
  11. p_1_2.merge_page(p1), p_1_2.merge_page(p2)で、見開きの空白ページp_1_2に、左右のページを追加します。
  12. writer.add_page(p_1_2)で、見開きのページをwriterに追加します。

補足

最終ページに空白を追加せず、左ページのみ追加する方法
from pypdf import PdfWriter, PdfReader, PageObject, Transformation


infile = './sample.pdf'  # 単ページのPDF
outfile = './sample_merge_2page.pdf'  # 見開きのPDFの保存ファイル

reader = PdfReader(infile)
writer = PdfWriter()

for i in range(0, len(reader.pages), 2):
    p1 = reader.pages[i]
    if i+1 == len(reader.pages):  # ページ総数が奇数の場合に、そのまま左ページのみ追加
        writer.add_page(p1)
        break
    else:
        p2 = reader.pages[i+1]
    width_1_2 = p1.mediabox.right + p2.mediabox.right
    height_1_2 = max(p1.mediabox.top, p2.mediabox.top)
    p_1_2 = PageObject.create_blank_page(width=width_1_2, height=height_1_2)

    # 見開きにするため、右ページ用のPDFを右に平行移動、mediaboxもそれに合わせて右に平行移動
    op = Transformation().translate(tx=p1.mediabox.right)
    p2.add_transformation(op)
    p2.mediabox.left = p1.mediabox.right
    p2.mediabox.right = p1.mediabox.right + p2.mediabox.right

    p_1_2.merge_page(p1)
    p_1_2.merge_page(p2)
    writer.add_page(p_1_2)

with open(outfile, mode='wb') as f:
    writer.write(f)

コードの説明(変更箇所のみ)

    if i+1 == len(reader.pages):  # ページ総数が奇数の場合、そのまま左ページのみ追加
        writer.add_page(p1)
        break

ページが奇数の場合は左ページのみwriter.add_page(p1)writerに追加して、それ以降の処理をスキップするため、breakする。

まとめ

pypdfを使い、単ページのPDFを見開きで結合する方法を紹介しました。最近、pypdf 3.0.0で変数名などが変更され、私自身PDFを見開きにする機会があり、色々とハマりどころがあったため本記事を書きました。誰かのお役に立てれば幸いです。

参考

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6