Pythonでborbを使ってPDFドキュメントを分割、結合、回転させる

Portable Document Format (PDF) は、WYSIWYG (What You See is What You Get) フォーマットではありません。

プラットフォームに依存せず、基盤となるオペレーティングシステムやレンダリングエンジンから独立したフォーマットとして開発されました。

これを実現するために、PDFはプログラミング言語のようなもので操作できるように構成されており、結果を得るためには一連の命令と操作に依存することになります。

実際、PDFはスクリプト言語であるPostScriptをベースにしています。

PostScriptは、デバイスに依存しない最初のページ記述言語でした。

このガイドでは、PDF文書の読み取り、操作、生成に特化したPythonのライブラリであるborbを使用することにします。

borbは、低レベルモデル(正確な座標やレイアウトにアクセスできる)と高レベルモデル(余白や位置などの正確な計算をレイアウトマネージャーに委ねることができる)の両方を提供します。

>
このガイドでは、Pythonでborbを使ってPDF文書を分割・結合する方法と、PDF文書内のページを回転させる方法について見ていきます。

PDF文書の分割と結合は、多くのユースケースの基礎となっています。

  • 請求書の処理(利用規約は不要なので、それらのページを削除することができます)。
  • ドキュメント(テストレポート、請求書、販促資料)にカバーレターを追加する。
  • 異種ソースからのテスト結果の集計
  • など。

borbのインストール

borbはGitHubのソースからダウンロードするか、pip経由でインストールすることができます。

$ pip install borb


borb を使って PDF を分割する

これを実演するには、いくつかのページを持つPDFが必要です。

まず、borbを使ってそのようなPDFを作成します。

このステップは任意です。

もちろん、その辺に転がっているPDFを代わりに使ってもかまいません。

from borb.pdf.canvas.color.color import HexColor
from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout
from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout
from borb.pdf.canvas.layout.text.paragraph import Paragraph
from borb.pdf.document import Document
from borb.pdf.page.page import Page
from borb.pdf.pdf import PDF
from decimal import Decimal


def create_document(heading_color: HexColor = HexColor("0b3954"), 
                    text_color: HexColor = HexColor("de6449"),
                    file_name: str = "output.pdf"):


d: Document = Document()


N: int = 10
    for i in range(0, N):

        # Create a new Page, and append it to the Document
        p: Page = Page()
        d.append_page(p)

        # Set the PageLayout of the new Page
        l: PageLayout = SingleColumnLayout(p)

        # Add the paragraph to identify the Page
        l.add(Paragraph("Page %d of %d" % (i+1, N),
                        font_color=heading_color,
                        font_size=Decimal(24)))

        # Add a Paragraph of dummy text                        
        l.add(Paragraph("""
                        Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
                        Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, 
                        when an unknown printer took a galley of type and scrambled it to make a type specimen book. 
                        It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. 
                        It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, 
                        and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
                        """,
                        font_color=text_color))

    # Persist the Document to disk
    with open(file_name, "wb") as pdf_out_handle:
        PDF.dumps(pdf_out_handle, d)


このサンプルコードでは、10ページからなるPDFドキュメントを生成します。

  • 各ページは “Page x of 10” で始まります。これは、後でページの識別を容易にするものです。
  • 各ページは1段落のテキストを含んでいます。

Python で PDF 文書を分割する。

では、このPDFを分割してみましょう。

まず、最初の5ページを含む前半と、残りのページを含む後半に分割します。

def split_half_half():


# Read PDF
  with open("output.pdf", "rb") as pdf_file_handle:
    input_pdf = PDF.loads(pdf_file_handle)


# Create two empty PDFs to hold each half of the split
  output_pdf_001 = Document()
  output_pdf_002 = Document()


# Split
  for i in range(0, 10):
    if i < 5:
      output_pdf_001.append_page(input_pdf.get_page(i))
    else:
      output_pdf_002.append_page(input_pdf.get_page(i))


# Write PDF
  with open("output_001.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_001)


# Write PDF
  with open("output_002.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_002)


最初の5ページを新しい Document に、次の5ページを2番目の新しい Document に抽出し、元のPDFを効果的に2つの小さなエンティティに分割しました。

>
これは get_page() メソッドの戻り値がそのまま append_page() に使用できるため、簡単に行うことができます。

このコードが意図したとおりに動作することを確認するために、結果のPDFを確認することができます。

>
最初のドキュメントは5ページ目で終わり、2番目のドキュメントは6ページ目で始まっています。

また、同様に他の条件に基づいて分割することもできます! 次の例では、すべての奇数ページを1つのPDFに、偶数ページを別のPDFに入れることによって、PDFを分割します。

def split_even_odd():


# Read PDF
  with open("output.pdf", "rb") as pdf_file_handle:
    input_pdf = PDF.loads(pdf_file_handle)

  # Rreate two empty PDFs to hold each half of the split
  output_pdf_001 = Document()
  output_pdf_002 = Document()


# Split
  for i in range(0, 10):
    if i % 2 == 0:
      output_pdf_001.append_page(input_pdf.get_page(i))
    else:
      output_pdf_002.append_page(input_pdf.get_page(i))


# Write PDF
  with open("output_001.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_001)


# Write PDF
  with open("output_002.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_002)


出来上がったPDFが前述の分割を表していることが確認できます。

Python で PDF 文書を結合する

次の例を実行するために、2つのPDFが必要です。

もしまだ持っていなければ、先ほどのコードを使ってPDFを生成してみましょう。

create_document(HexColor("247B7B"), HexColor("78CDD7"), "output_001.pdf")
create_document(file_name="output_002.pdf")


しかし、ページだけでなく、ドキュメント全体を他のドキュメントに追加することができます。

しかし、時には文書を分割して(最後のページを切り取って)から別の文書と結合したいこともあるでしょう。

両方のPDFを連結して)完全に結合することもできますが、そうしたい場合は、前と同じように append_page() 関数を使って、最初のPDFのいくつかのページを2番目のPDFに追加するだけでもできます。

まずは全体を連結することから始めてみましょう。

def concatenate_two_documents():


# Read first PDF
  with open("output_001.pdf", "rb") as pdf_file_handle:
    input_pdf_001 = PDF.loads(pdf_file_handle)

  # Read second PDF
  with open("output_002.pdf", "rb") as pdf_file_handle:
    input_pdf_002 = PDF.loads(pdf_file_handle)

  # Build new PDF by concatenating two inputs
  output_document = Document()
  output_document.append_document(input_pdf_001)
  output_document.append_document(input_pdf_002)

  # Write PDF
  with open("output.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_document)


このコードは次のようになります。

PythonでPDFドキュメントのページを回転させる

PDF 文書のページは、90 度の倍数で回転させることができます。

このような操作により、ランドスケープモードとポートレートモードを簡単に切り替えることができます。

次の例では、先ほど作成した入力PDFの1つのページを回転させます。

def rotate_first_page():
  # Read PDF
  with open("output_001.pdf", "rb") as pdf_file_handle:
    input_pdf_001 = PDF.loads(pdf_file_handle)


# Rotate page
  input_pdf_001.get_page(0).rotate_left()  

  # Write PDF to disk
  with open("output.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, input_pdf_001)


出来上がったPDFはこのような感じになります。

結論

このガイドでは、PDF文書を結合および分割する方法について見てきました。

また、いくつかのページを回転させることによって、既存のPDFを変更しました。

タイトルとURLをコピーしました