請求書、契約書、報告書などの業務文書は、数十ページから数百ページのPDFにまとめられていることがあります。しかし、実際に共有したいのは、その中の一部だけというケースも少なくありません。
たとえば、取引先に特定のページだけを送付したい場合や、部署ごとに必要な章だけを配布したい場合、元のPDFをそのまま扱うより、必要なページを切り出して別ファイルにした方が扱いやすくなります。
また、スキャンした資料や横長の図表など、1ページが極端に大きなPDFでは、画面表示や印刷時に縮小されて文字が読みにくくなることがあります。このような場合は、1ページを複数のページに分けることで、閲覧しやすいサイズに調整できます。
本記事では、Spire.PDF for Python を使ってPDFを分割する方法を紹介します。PDF全体を1ページずつ分ける方法、必要なページだけを抽出する方法、さらに大きな1ページを複数ページに分割する方法まで、コード例を使って解説します。
環境を準備する
ここでは Spire.PDF for Python を使用します。PDFの読み込みやページ操作に対応しており、ページ単位の分割からページサイズを変更した再分割まで、Pythonからまとめて処理できます。
まず、以下のコマンドでインストールします。
pip install Spire.PDF
インストール後、スクリプトで必要なモジュールを読み込みます。
from spire.pdf.common import *
from spire.pdf import *
以降のサンプルでは、PdfDocument にPDFを読み込んで処理します。
PDFを1ページずつ分割する
PDFの全ページをそれぞれ独立したファイルにしたい場合は、PdfDocument.Split() を使うと簡単です。
出力ファイル名にはテンプレートを指定でき、{0} の部分にページ番号が入ります。そのため、ページ数が多いPDFでも個別にファイル名を指定する必要はありません。
from spire.pdf.common import *
from spire.pdf import *
inputFile = "./Data/SplitDocument.pdf"
# PDFを読み込む
doc = PdfDocument()
doc.LoadFromFile(inputFile)
# ページごとに分割して保存
doc.Split("SplitDocument-{0}.pdf")
doc.Close()
たとえば SplitDocument-{0}.pdf を指定すると、ページ番号を含むファイル名で各ページが出力されます。
出力先のフォルダーを指定したい場合は、ファイル名のテンプレートにパスを含めることもできます。
この方法は、「PDFをページ単位のファイルに分けたい」というケースに向いています。請求書を1枚ずつ分けたり、会議資料をページ単位で個別に管理したりする場合にも利用できます。
必要なページだけを抽出する
PDF全体を分割するのではなく、特定のページだけを抜き出したい場合は、新しい PdfDocument を作成し、必要なページを追加します。
以下の例では、元PDFの2ページ目と3ページ目を新しいPDFにコピーしています。
from spire.pdf.common import *
from spire.pdf import *
inputFile = "./Data/Sample.pdf"
outputFile = "SplitFileByParticularPage.pdf"
# 元のPDFを読み込む
oldPdf = PdfDocument()
oldPdf.LoadFromFile(inputFile)
# 出力用のPDFを作成
newPdf = PdfDocument()
# 2ページ目と3ページ目を抽出
for i in range(1, 3):
# 元ページと同じサイズのページを追加
page = newPdf.Pages.Add(
oldPdf.Pages[i].Size,
PdfMargins(0.0)
)
# 元ページをテンプレートとして描画
oldPdf.Pages[i].CreateTemplate().Draw(
page,
PointF(0.0, 0.0)
)
# 保存
newPdf.SaveToFile(outputFile)
newPdf.Close()
oldPdf.Close()
Pages[i] のインデックスは0から始まるため、Pages[1] は2ページ目、Pages[2] は3ページ目に対応します。
この例では、元ページと同じサイズのページを作成し、CreateTemplate().Draw() で元ページの内容を描画しています。PdfMargins(0.0) を指定しているため、余計な余白を追加せずに元のページサイズを維持できます。
連続したページを抽出する場合は range() の範囲を変更するだけです。たとえば4ページ目から8ページ目までなら、次のように指定できます。
for i in range(3, 8):
# ページをコピーする処理
必要なページが連続していない場合は、ページ番号をリストで管理する方法もあります。
pages = [0, 2, 5]
for i in pages:
# ページをコピーする処理
この方法なら、必要なページだけを選んで1つのPDFにまとめられます。
1ページを複数ページに分割する
縦長のスキャン資料や大きな図表など、1ページのサイズが大きすぎるPDFでは、単純にページを切り出すだけでは十分ではありません。
このような場合は、新しいPDFのページサイズを小さく設定し、元ページの内容を複数のページに分けて描画します。
たとえば、元ページの高さを半分に設定すれば、縦方向に2ページへ分割できます。Spire.PDFでは PdfTextLayout の Break と Layout を設定することで、ページに収まらない内容を次のページへ送ることができます。
from spire.pdf.common import *
from spire.pdf import *
inputFile = "./Data/PDFTemplate_N.pdf"
outputFile = "SplitAPageIntoMultipage.pdf"
# PDFを読み込む
doc = PdfDocument()
doc.LoadFromFile(inputFile)
# 分割対象のページを取得
page = doc.Pages[0]
# 出力用のPDFを作成
newPdf = PdfDocument()
# ページ余白をなくす
newPdf.PageSettings.Margins.All = 0.0
# 元ページの幅を維持し、高さを半分にする
newPdf.PageSettings.Width = page.Size.Width
newPdf.PageSettings.Height = page.Size.Height / 2
# 新しいページを追加
newPage = newPdf.Pages.Add()
# ページに収まらない内容を次のページへ送る設定
layout = PdfTextLayout()
layout.Break = PdfLayoutBreakType.FitPage
layout.Layout = PdfLayoutType.Paginate
# 元ページの内容を新しいページへ描画
page.CreateTemplate().Draw(
newPage,
PointF(0.0, 0.0),
layout
)
# 保存
newPdf.SaveToFile(outputFile)
newPdf.Close()
doc.Close()
PageSettings.Height を元ページの高さの半分に設定しているため、縦方向に2ページへ分割されます。
3ページに分けたい場合は、次のように変更します。
newPdf.PageSettings.Height = page.Size.Height / 3
逆に、横長のページを左右に分けたい場合は、幅を半分にします。
newPdf.PageSettings.Width = page.Size.Width / 2
newPdf.PageSettings.Height = page.Size.Height
この方法は、ページサイズを変更したうえで元ページの内容を再配置する仕組みです。そのため、単純にPDFページを画像として切り分ける処理とは異なります。
特にスキャンPDFなど、ページ全体が1枚の画像として構成されている場合は、分割結果を実際に確認することをおすすめします。
実践的な使い方
複数のPDFをまとめて分割する
同じ処理を多数のPDFに対して行う場合は、os モジュールと組み合わせると便利です。
以下の例では、指定したフォルダー内にあるPDFをすべてページ単位に分割し、output_dir に保存します。
import os
from spire.pdf.common import *
from spire.pdf import *
input_dir = "./Data/PdfFiles"
output_dir = "./Output/SplitFiles"
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.lower().endswith(".pdf"):
continue
input_path = os.path.join(input_dir, filename)
prefix = os.path.splitext(filename)[0]
# 元のファイル名を含めた出力パターンを作成
pattern = os.path.join(
output_dir,
f"{prefix}-{{0}}.pdf"
)
doc = PdfDocument()
doc.LoadFromFile(input_path)
doc.Split(pattern)
doc.Close()
print(f"分割完了: {filename}")
元のファイル名を出力ファイルに含めておくことで、複数のPDFを処理してもファイル名が重複しにくくなります。
たとえば、
Invoice.pdf
Report.pdf
Contract.pdf
を処理すると、それぞれのファイル名をベースにした分割ファイルを作成できます。
ファイル数が多い場合は、各 PdfDocument の処理が終わったら Close() を呼び出し、使用したリソースを解放しておくことも重要です。
ページ番号をファイル名に付ける
Split() では、出力ファイル名のテンプレートに {0} を指定できます。ページ番号の表記を含めたい場合は、このプレースホルダーを利用できます。公式のPythonサンプルでも、SplitDocument-{0}.pdf のようなパターンが使われています。
ファイル名を人間が確認する必要がある場合は、元のファイル名と組み合わせておくと管理しやすくなります。
pattern = "./Output/Invoice-{0}.pdf"
doc.Split(pattern)
なお、ライブラリのバージョンや使用する Split() のオーバーロードによって、ページ番号の開始値を指定できる場合があります。ファイル名の規則を厳密に決める場合は、使用中のバージョンのAPI仕様を確認してください。
分割後のPDFを確認する
PDFの分割は単純なファイル操作に見えますが、元PDFの構造によっては結果を確認した方がよいケースがあります。
特に次のようなPDFでは、分割後のファイルを一度開いて確認することをおすすめします。
- 回転設定が使われているPDF
- 複雑なレイアウトを含むPDF
- 注釈やフォームフィールドを含むPDF
- スキャン画像を中心としたPDF
- 外部ファイルや特殊なリンクを含むPDF
単純なページ分割なら Split() が便利ですが、特定ページだけを抽出したい場合は、必要なページを新しい PdfDocument にコピーする方法の方が処理内容を明確にできます。
まとめ
PythonとSpire.PDFを使えば、PDFの分割処理を用途に応じて自動化できます。
-
ページ単位で分割する →
PdfDocument.Split()を使う -
必要なページだけ抽出する →
Pages.Add()とCreateTemplate().Draw()を組み合わせる -
大きな1ページを複数ページに分ける →
PageSettingsとPdfTextLayoutを使って再配置する -
複数のPDFを一括処理する →
osと組み合わせてフォルダー単位で処理する - 長尺ページを分割する → ページの幅・高さを調整して、内容を複数ページへ配置する
PDFをページ単位で管理したいだけなら Split() が最もシンプルです。一方、必要なページだけを抜き出したい場合や、1ページのサイズそのものを変更したい場合は、それぞれに適したAPIを使い分けると処理を組み立てやすくなります。
実際の業務では、まず少数のファイルで分割結果を確認してから、フォルダー単位の一括処理へ広げると、レイアウトやページ構成の問題にも気付きやすくなります。