エンジニアとしての市場価値を測りませんか?PR

企業からあなたに合ったオリジナルのスカウトを受け取って、市場価値を測りましょう

3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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
import copy

実行時の各種バージョン

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で作成したコードは、こちらにあります。

方法

2つの方法を紹介します。
どちらも出力されたPDFの表示に変わりはありません。方法1の方がコードがシンプルですが、以下の違いがあります。

方法1と方法2の違い概要

  • 方法1ではmediaboxを見開きのページの座標で表示
  • 方法2ではmediaboxを単ページ単位の座標で表示

方法1と方法2の違いを図で説明
image.png

単純に単ページで表示されることのみが目的の場合は方法1で十分です。ただ、単ページに分割後にpypdfなどで編集される方は、mediaboxが単ページ単位の方が編集しやすいと思うので、方法2をお勧めします。ちなみに、単ページに分割後のPDFでもmediaboxの情報は残ります。

方法1(mediaboxを見開きのページの座標で表示)

単純に単ページで表示されることのみが目的の場合はこちらで十分です。

from pypdf import PdfWriter, PdfReader, PageObject, Transformation
import copy


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

reader = PdfReader(infile)
writer = PdfWriter()

for page in reader.pages:
    p1 = copy.copy(page)
    p2 = copy.copy(page)

    p1.mediabox.right = page.mediabox.right / 2
    p2.mediabox.left = page.mediabox.right / 2

    writer.add_page(p1)
    writer.add_page(p2)

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

コードの説明

  1. 見開きページの左ページと右ページ用にp1 = copy.copy(page), p2 = copy.copy(page)を用意します。
  2. p1は見開きの表示領域になっているので、左半分になるように変更します。p1.mediabox.right = page.mediabox.right / 2で、見開きページの表示領域(mediabox)の半分の座標が、p1の中のmediaboxの右端の座標に位置するように変更します。これにより左半分のみ表示されます。
  3. 同様に、p2も見開きの表示領域になっているので、右半分になるように変更します。p2.mediabox.left = page.mediabox.right / 2で、見開きページのmediaboxの半分の座標が、p2の中のmediaboxの左端の座標に位置するように変更します。これにより右半分のみ表示されます。
  4. writer.add_page(p1), writer.add_page(p2)で、単ページをwriterに追加します。

方法2(mediaboxを単ページ単位の座標で表示)

pypdfなどで編集される方はmediaboxが単ページ単位の方が編集しやすいので、こちらの方法も紹介します。

from pypdf import PdfWriter, PdfReader, PageObject, Transformation
import copy


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

reader = PdfReader(infile)
writer = PdfWriter()

for page in reader.pages:
    p1 = copy.copy(page)
    p2 = copy.copy(page)

    # mediaboxの左側(p2.mediabox.left)が0になるように平行移動
    op = Transformation().translate(tx=-page.mediabox.right / 2)
    p2.add_transformation(op)

    p1.mediabox.right = page.mediabox.right / 2
    p2.mediabox.right = page.mediabox.right / 2

    writer.add_page(p1)
    writer.add_page(p2)

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

コードの説明

  1. 見開きページの左ページと右ページ用にp1 = copy.copy(page), p2 = copy.copy(page)を用意します。
  2. op = Transformation().translate(tx=-page.mediabox.right / 2)で、左方向に見開きの横幅の半分だけ平行移動する変換を用意します。
  3. p2.add_transformation(op)opを適用します。これにより、今p2の表示領域は右ページ+余白になっています。(p2のmediaboxは平行移動していないので注意してください。)
  4. p1は見開きの表示領域になっているので、左半分になるように変更します。p1.mediabox.right = page.mediabox.right / 2で、見開きページの表示領域(mediabox)の半分の座標が、p1の中のmediaboxの右端の座標に位置するように変更します。これにより左半分のみ表示されます。
  5. p2右ページ+余白になっているので、余白を表示しないために、p2のmediaboxを変更します。p2.mediabox.left = page.mediabox.right / 2で、見開きページのmediaboxの半分の座標が、p2の中のmediaboxの右端の座標に位置するように変更します。これにより右半分のみ表示されます。
  6. writer.add_page(p1), writer.add_page(p2)で、単ページをwriterに追加します。

まとめ

pypdfを使い、見開きのPDFを単ページに分割する方法を紹介しました。最近、pypdf 3.0.0で変数名などが変更され、私自身PDFを見開きにする機会があり、色々とハマりどころがあったため本記事を書きました。mediaboxは、PDF保存後も残っているので次回編集する時にハマりやすいので、場合によって方法2も使っていきましょう。この記事が誰かの役に立てば幸いです。

参考

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?