概要
pypdfを使い、下図のような見開きのPDFを単ページに分割する方法を紹介します。
各種インポート
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で十分です。ただ、単ページに分割後に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)
コードの説明
- 見開きページの左ページと右ページ用に
p1 = copy.copy(page)
,p2 = copy.copy(page)
を用意します。 -
p1
は見開きの表示領域になっているので、左半分になるように変更します。p1.mediabox.right = page.mediabox.right / 2
で、見開きページの表示領域(mediabox)の半分の座標が、p1
の中のmediaboxの右端の座標に位置するように変更します。これにより左半分のみ表示されます。 - 同様に、
p2
も見開きの表示領域になっているので、右半分になるように変更します。p2.mediabox.left = page.mediabox.right / 2
で、見開きページのmediaboxの半分の座標が、p2
の中のmediaboxの左端の座標に位置するように変更します。これにより右半分のみ表示されます。 -
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)
コードの説明
- 見開きページの左ページと右ページ用に
p1 = copy.copy(page)
,p2 = copy.copy(page)
を用意します。 -
op = Transformation().translate(tx=-page.mediabox.right / 2)
で、左方向に見開きの横幅の半分だけ平行移動する変換を用意します。 -
p2.add_transformation(op)
でop
を適用します。これにより、今p2
の表示領域は右ページ+余白になっています。(p2のmediaboxは平行移動していないので注意してください。) -
p1
は見開きの表示領域になっているので、左半分になるように変更します。p1.mediabox.right = page.mediabox.right / 2
で、見開きページの表示領域(mediabox)の半分の座標が、p1
の中のmediaboxの右端の座標に位置するように変更します。これにより左半分のみ表示されます。 -
p2
は右ページ+余白になっているので、余白を表示しないために、p2
のmediaboxを変更します。p2.mediabox.left = page.mediabox.right / 2
で、見開きページのmediaboxの半分の座標が、p2
の中のmediaboxの右端の座標に位置するように変更します。これにより右半分のみ表示されます。 -
writer.add_page(p1)
,writer.add_page(p2)
で、単ページをwriter
に追加します。
まとめ
pypdfを使い、見開きのPDFを単ページに分割する方法を紹介しました。最近、pypdf 3.0.0で変数名などが変更され、私自身PDFを見開きにする機会があり、色々とハマりどころがあったため本記事を書きました。mediaboxは、PDF保存後も残っているので次回編集する時にハマりやすいので、場合によって方法2も使っていきましょう。この記事が誰かの役に立てば幸いです。
参考