📃

PythonでPDFにテキストを書き込む方法

2024/06/20に公開

はじめに

以前業務の自動化をするためにPDFを操作するデスクトップアプリを開発しました。処理内容としては

  1. PDFの中のテキストを読み取る
  2. 1.のテキストデータを元に算出した情報をPDFにテキスト書き込み & ファイル名変更
  3. 2.で変更したファイル名に記載した伝票No.同じPDFを結合

という処理のデスクトップアプリをPythonで開発しました。

その時に使用したPDFへテキストを書き込む方法を書きます。

環境

  • Windows11
  • Python 3.9.13

処理概要

前提として処理の内容を理解しておいた方が理解しやすいのでここで説明します。
主に使用するライブラリはPyPDF2ReportLabで、処理の内容としては

  1. 透明のPDFを作成する
  2. 1.のPDFに書き込みたいテキストを印字する
  3. そのPDFを書き込みたいPDFに上から被せて1枚のPDFにする
  4. 処理したいPDFが複数枚ある場合は1枚ずつ1~3をおこなう

という方法でPDFに書き込みをします。

ライブラリのインストール

pip install PyPDF2 reportlab

準備

まずは処理する用の真っ白なPDFを用意するためのPythonファイルを用意します。
下記のコードを実行するとinput.pdfファイルが出力されます。
引数の数字を変更することでPDFの枚数を変更することができます。

create_pdf.py
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter

def create_blank_pdf(pages, output_pdf):
    c = canvas.Canvas(output_pdf, pagesize=letter)
    for _ in range(pages):
        c.showPage()
    c.save()

# 使用例: 5ページの真っ白なPDFを生成
output_pdf = 'input.pdf'
create_blank_pdf(5, output_pdf)

基本的なコードの構成

以下に、PDFにテキストを書き込むための基本的なコードを示します。このコードでは、先ほど作成した真っ白なPDFにページ番号を追加する例を説明します。

main.py
# PDFを読み込み、結合するのに使用します。
import PyPDF2
# 作成したPDFをメモリとして保持するのに使用します。
import io
# 新しいPDFを生成し、テキストを描画するのに使用します。
from reportlab.pdfgen import canvas
# PDFのページサイズを設定するのに使用します。
from reportlab.lib.pagesizes import letter
# テキストの色を赤に設定するのに使用します。
from reportlab.lib.colors import red

def add_page_numbers(input_pdf, output_pdf):
    # 入力PDFを読み込む
    with open(input_pdf, 'rb') as f:
        pdf_reader = PyPDF2.PdfFileReader(f)
        pdf_writer = PyPDF2.PdfFileWriter()
        
        # ページ番号のPDFをメモリ上に作成
        packet = io.BytesIO()
        can = canvas.Canvas(packet, pagesize=letter)
        
        # 各ページにテキストを追加
        for page_num in range(pdf_reader.getNumPages()):
            # フォントの設定
            can.setFont("Helvetica-Bold", 12)
            can.setFillColor(red)
            # 書き込む位置の指定
            can.drawString(500, 10, f"Page {page_num + 1}")
            can.showPage()
        can.save()
        
        packet.seek(0)
        new_pdf = PyPDF2.PdfFileReader(packet)
        
        # 元のPDFにページ番号を重ねる
        for page_num in range(pdf_reader.getNumPages()):
            page = pdf_reader.getPage(page_num)
            page.mergePage(new_pdf.getPage(page_num))
            pdf_writer.addPage(page)
        
        # 出力PDFを保存
        with open(output_pdf, 'wb') as output_f:
            pdf_writer.write(output_f)

# 使用例
input_pdf = 'input.pdf'
output_pdf = 'output.pdf'
add_page_numbers(input_pdf, output_pdf)

コードの詳細説明

既存のPDFを読み込む

PyPDF2を使用して、既存のPDFを読み込みます。

with open(input_pdf, 'rb') as f:
    pdf_reader = PyPDF2.PdfFileReader(f)
    pdf_writer = PyPDF2.PdfFileWriter()

透明なPDFを作成

ReportLabを使用して、各ページにページ番号を追加する透明なPDFを作成します。

packet = io.BytesIO()
can = canvas.Canvas(packet, pagesize=letter)

透明なPDFに書き込み

ここでPDFに書き込むテキストのフォントの設定、色、書き込む位置の設定を行います。

for page_num in range(pdf_reader.getNumPages()):
    # フォントの設定
    can.setFont("Helvetica-Bold", 12)
    can.setFillColor(red)
    # 書き込む位置の指定
    can.drawString(500, 10, f"Page {page_num + 1}")
    can.showPage()
can.save()
drawStringメソッドの概要

考え方としてはX軸が横方向でY軸が縦方向、X軸の0は左端でY軸の0は下端になります。
下記がコードとイメージになります。

drawString(x, y, text)
(0, height)                           (width, height)
  +--------------------------------------+
  |                                      |
  |                                      |
  |                                      |
  |                                      |
  |                                      |
  |                                      |
  |                                      |
  |                                      |
  |                                      |
  +--------------------------------------+
(0, 0)                                (width, 0)

新しいPDFを既存のPDFに重ねる

PyPDF2mergePageメソッドを使用して、透明なPDFを既存のPDFに重ねます。

for page_num in range(pdf_reader.getNumPages()):
    page = pdf_reader.getPage(page_num)
    page.mergePage(new_pdf.getPage(page_num))
    pdf_writer.addPage(page)

結果を保存

最終的なPDFをファイルとして保存します。

with open(output_pdf, 'wb') as output_f:
    pdf_writer.write(output_f)

結果

下記の通り5枚ともPDFに印字がされています。

最後に

この記事ではPDFにテキストを書き込む方法を紹介しましたが、他のライブラリを使用すればPDFの結合や中のテキストを抽出することも可能なので、他のライブラリも確認してみてください。

Discussion