【Python】既存のPDFにテキスト(英字と日本語)を書き込む方法

時計 2023.05.21 / 時計

【Python】既存のPDFにテキスト(英字と日本語)を書き込む方法

記事ではPythonによる、既存のPDFテキスト書き込む方法について解説していきます。

PDFはビジネスで社内外のファイルのやり取りで頻繁に利用されるファイル形式です。Pythonを利用することでPDFへの書き込み作業を自動化することができます。

例えばエクセルに入力した情報をPDFの任意の箇所に転記することや、データベースに登録した情報をPDFに書き込むといったことができます。

本記事ではまず最初に覚えておくべき「PDFにテキストを書き込む方法」を解説しています。ここではReportLabとPyPDF2を利用しています。

ぜひ本記事を通して、PDFにテキストを書き込む方法について理解を深めてください。

使用するライブラリについて:ReportLabとPyPDF2

ReportLabとは

ReportLabとはPDFを生成するライブラリです。白いキャンバスに絵を描いていくかのように、Canvasというオブジェクトに文字を書き込み、それをPDFとして保存します。

すべて英語ですがReportLabの公式サイトとマニュアルへのリンクを以下に記します。

ReportLab公式サイト

ReportLabマニュアルサイト

ReportLabを初めて利用する方は基本的な使用方法を以下記事でご確認ください。

PyPDF2とは

PyPDF2はPythonで主に利用されるPDFを操作するライブラリの一つです。PyPDF2ではPDFの結合や分割、テキストや画像の抽出などの操作を可能とします。

ReportLabは新規にPDFを作成しますが、PyPDF2は既存のPDFを読み込んでの操作や解析を得意とするライブラリです。

PythonでPDFを操作するアプリケーションを作成する場合、PyPDF2はなくはならない存在です。

Python:既存のPDFにテキストを書き込む方法

Pythonで既存のPDFにテキストを書き込むプログラムを作成していきます。プログラムは以下の流れで動作し、最終的に既存のPDFに指定したテキストを書き込みます。

  1. 使用するライブラリのインポート
  2. 新規でPDFを生成し、テキストを書き込む
  3. 新規作成したPDFと既存のPDFファイルを読み込む
  4. 2つのPDFをマージ(合体)させ保存

上記の流れをよりわかりやすく言うと、ReportLabで新規作成したPDFを既存のPDFの上に貼り付けるということです。

それぞれの方法について次項より詳しく解説していきます。

1.使用するライブラリのインポート

ここではReportLabとPyPDF2を使用します。これらは標準ライブラリではないため、pipコマンドでインストールしましょう。

pip install reportlab pypdf2

次に必要なモジュールや関数をインポートします。スクリプトの先頭に以下を記述してください。

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4, portrait
from reportlab.lib.units import mm
from PyPDF2 import PdfWriter, PdfReader
import io

2.新規でPDFを生成し、テキストを書き込む

ReportLabを使ってPDFを新規で生成します。PDFのサイズはA4サイズを指定します。ここで生成するPDFは単にテキストを書き込み、既存のPDF上に貼り付けるのみに使用します。そのためわざわざファイルとして保存する必要はないです。

そこでここではio.BytesIO()を使用します。io.BytesIO()はデータをメモリ上にバイナリデータとしてバッファ(一時的にメモリに保存すること)する機能です。

以下コードのようにBytesIOオブジェクトを生成し、CanvasでPDFを生成する際にBytesIOオブジェクトを第一引数に指定します。

### PDFを生成、サイズはA4 ###
io_object = io.BytesIO()    # BytesIOオブジェクトの生成
pdf = canvas.Canvas(io_object, pagesize=portrait(A4))

次に生成したPDFにテキストを書き込みます。テキストのフォントとサイズは「Times-Bold」の「12ピクセル」で指定しています。

### フォント、サイズを設定 ###
pdf.setFont('Times-Bold', 12)
### 文字を描画 ###
pdf.drawString(15*mm, 280*mm, 'test')
pdf.showPage()
pdf.save()

3.新規作成したPDFと既存のPDFファイルを読み込む

新規で作成したPDFを変数new_pdfに格納します。

### BytesIOの読み込み ###
io_object.seek(0)
new_pdf = PdfReader(io_object)

次に既存のPDF(ここではoffice54.pdf)を変数existing_pdfに格納し、そのPDFの1ページ目を変数existing_pdf_pageに格納しています。

### 既存PDFの読み込み###
pdf_file_path = "office54.pdf"
existing_pdf = PdfReader(open(pdf_file_path, 'rb'), strict=False)
existing_pdf_page = existing_pdf.pages[0]

4.2つのPDFをマージ(合体)させ保存

既存のPDF上に新規で作成したPDFのテキストを張り付けるにはmerge_page()メソッドを使用します。

### 新規PDFと既存のPDFをマージ ###
output = PdfWriter()
existing_pdf_page.merge_page(new_pdf.pages[0])
output.add_page(existing_pdf_page)

最後に以下のようにコードを記述し、マージされたPDFを保存します。

### PDFを保存 ###
output_name = " output.pdf"
output_stream = open(output_name, 'wb')
output.write(output_stream)
output_stream.close()

すべてのソースコード

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4, portrait
from reportlab.lib.units import mm
from PyPDF2 import PdfWriter, PdfReader
import io

### PDFを生成、サイズはA4 ###
io_object = io.BytesIO()    # BytesIOオブジェクトの生成
pdf = canvas.Canvas(io_object, pagesize=portrait(A4))
### フォント、サイズを設定 ###
pdf.setFont('Times-Bold', 12)
### 文字を描画 ###
pdf.drawString(15*mm, 280*mm, 'test')
pdf.showPage()
pdf.save()
### BytesIOの読み込み ###
io_object.seek(0)
new_pdf = PdfReader(io_object)
### 既存PDFの読み込み###
pdf_file_path = "office54.pdf"
existing_pdf = PdfReader(open(pdf_file_path, 'rb'), strict=False)
existing_pdf_page = existing_pdf.pages[0]
### 新規PDFと既存のPDFをマージ ###
output = PdfWriter()
existing_pdf_page.merge_page(new_pdf.pages[0])
output.add_page(existing_pdf_page)
### PDFを保存 ###
output_name = "output.pdf"
output_stream = open(output_name, 'wb')
output.write(output_stream)
output_stream.close()

PDFに日本語のテキストを書き込む

上記での方法では日本語のテキストを書き込むことはできません。日本語テキストをPDFに書き込みたい場合は異なるフォント(日本語のフォント)を使用する必要あります。

以下に日本語フォントを利用する例を記述しますので、参考にしてください。

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
…
### フォント、サイズを設定 ###
pdfmetrics.registerFont(UnicodeCIDFont('HeiseiKakuGo-W5'))
pdf.setFont('HeiseiKakuGo-W5', 12)
### 文字を描画 ###
pdf.drawString(15*mm, 280*mm, 'テスト')
…