morikomorou’s blog

自分が学んだことなどの備忘録的なやつ

【python】ReportlabをつかってPDFファイルを作成する


はじめに

仕事でデータを分析したり、グラフ化して、PDFのレポートを作成するといったことが結構あります。
意外と作成がめんどくさいのでpythonで自動でやれないかと思いpythonでPDFの作成方法について調べてみました。
Reportlabというライブラリを使いこなせればPDFファイルの生成を思うがままにやれるようなので実際に使ってみます。




Reportlabを使ってみる

準備

まずは以下の呪文でインストールします

pip install reportlab

実際にPDFを生成し文字を入力してみる

さっそく文字の入ったPDFファイルを生成してみましょう。
canvasを作成して、そこに文字や画像等を位置指定して書き込んでいく形です。
文字の入力は.drawStringメソッドを使って実施します。

from reportlab.lib.pagesizes import A4, mm, portrait
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import cidfonts
from reportlab.pdfgen import canvas

# 日本語フォントの登録
pdfmetrics.registerFont(cidfonts.UnicodeCIDFont("HeiseiKakuGo-W5"))

# テンプレートの生成
pdf = canvas.Canvas("hello_world_test.pdf", pagesize=portrait(A4)) # "hello_world_test.pdf"という名前で縦書きA4サイズのキャンバスを生成
pdf.saveState() # キャンバスを初期化

width, height = A4   # 595px, 842px

# 文字の入力
pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(15*mm, height - 15*mm, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定
pdf.drawString(15*mm, height - 30*mm, 'こんにちは、世界!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(100*mm, height / 2, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

pdf.save() # PDFファイルに保存

結果はhello_world_test.pdfという名前で以下のように出力できました。

reportlabのCanvasクラスのdrawStringメソッドを使えば指定した位置に文字を入力できます。
位置はページの左下をx,y=0として指定し、指定した位置が入力したい文字列の左下の座標になります。




画像の挿入

次は画像を挿入してみましょう。
画像はCanvasクラスのdrawImageメソッドで挿入できます。

from reportlab.lib.pagesizes import A4, mm, portrait
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import cidfonts
from reportlab.pdfgen import canvas

# 日本語フォントの登録
pdfmetrics.registerFont(cidfonts.UnicodeCIDFont("HeiseiKakuGo-W5"))

# テンプレートの生成
pdf = canvas.Canvas("hello_world_test.pdf", pagesize=portrait(A4)) # "hello_world_test.pdf"という名前で縦書きA4サイズのキャンバスを生成
pdf.saveState() # キャンバスを初期化

width, height = A4   # 595px, 842px

# 文字の入力
pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(15*mm, height - 15*mm, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定
pdf.drawString(15*mm, height - 30*mm, 'こんにちは、世界!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(100*mm, height / 2, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

# 画像の挿入
pdf.drawImage('rennai_kaeruka.png',15*mm, height - 70*mm, 30*mm, 30*mm) # 画像ファイルパス、挿入位置、画像サイズを引数に指定して画像を挿入する

pdf.save() # PDFファイルに保存

画像も指定した位置に貼り付けができました。




表の挿入

表の罫線の挿入にはCanvasのgridメソッドを使えば可能です。

from reportlab.lib.pagesizes import A4, mm, portrait
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import cidfonts
from reportlab.pdfgen import canvas

# 日本語フォントの登録
pdfmetrics.registerFont(cidfonts.UnicodeCIDFont("HeiseiKakuGo-W5"))

# テンプレートの生成
pdf = canvas.Canvas("hello_world_test.pdf", pagesize=portrait(A4)) # "hello_world_test.pdf"という名前で縦書きA4サイズのキャンバスを生成
pdf.saveState() # キャンバスを初期化

width, height = A4   # 595px, 842px

# 文字の入力
pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(15*mm, height - 15*mm, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定
pdf.drawString(15*mm, height - 30*mm, 'こんにちは、世界!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(100*mm, height / 2, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

# 画像の挿入
pdf.drawImage('rennai_kaeruka.png',15*mm, height - 70*mm, 30*mm, 30*mm) # 画像ファイルパス、挿入位置、画像サイズを引数に指定して画像を挿入する

# 表の挿入
xlist = (15*mm, 40*mm, 70*mm, 100*mm, 150*mm, )
ylist = (height - 170*mm, height - 180*mm, height - 190*mm, height - 200*mm, )
pdf.grid(xlist, ylist) # 引数にx,y軸の罫線位置を指定して表を描画

pdf.save() # PDFファイルに保存

いい感じに表が書けました。表の中身はすごく面倒ですが、この場合はdrawStringメソッドで逐一位置を指定して入力するしかなさそうです…

次ページの作成

次ページはCanvasクラスのshowPageメソッドで作成できます。
showPageを実行したあと、文字等を挿入すると次ページに勝手に書かれます。
その際はフォントやサイズの指定がリセットされるので再度設定しておく必要がありそうです。

from reportlab.lib.pagesizes import A4, mm, portrait
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import cidfonts
from reportlab.pdfgen import canvas

# 日本語フォントの登録
pdfmetrics.registerFont(cidfonts.UnicodeCIDFont("HeiseiKakuGo-W5"))

# テンプレートの生成
pdf = canvas.Canvas("hello_world_test.pdf", pagesize=portrait(A4)) # "hello_world_test.pdf"という名前で縦書きA4サイズのキャンバスを生成
pdf.saveState() # キャンバスを初期化

width, height = A4   # 595px, 842px

# 文字の入力
pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(15*mm, height - 15*mm, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定
pdf.drawString(15*mm, height - 30*mm, 'こんにちは、世界!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(100*mm, height / 2, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

# 画像の挿入
pdf.drawImage('rennai_kaeruka.png',15*mm, height - 70*mm, 30*mm, 30*mm) # 画像ファイルパス、挿入位置、画像サイズを引数に指定して画像を挿入する

# 表の挿入
xlist = (15*mm, 40*mm, 70*mm, 100*mm, 150*mm, )
ylist = (height - 170*mm, height - 180*mm, height - 190*mm, height - 200*mm, )
pdf.grid(xlist, ylist) # 引数にx,y軸の罫線位置を指定して表を描画

# 次ページの作成
pdf.showPage()
pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(15*mm, height - 15*mm, '次ページです')

pdf.save() # PDFファイルに保存

結果は以下の通りで2ページ目が追加されそっちに文字が入力できていることが確認できます。




いろいろ問題点

上記で一通りPDFの作成方法をサラッと紹介しましたが、いろいろ問題点はあります。
まず毎回文字打つときに入力位置を指定しないといけなかったり、以下のプログラムのように長い文章を入力したいときは自動で改行せずはみ出してしまったりと、使いづらいことこの上ないです。

from reportlab.lib.pagesizes import A4, mm, portrait
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import cidfonts
from reportlab.pdfgen import canvas

# 日本語フォントの登録
pdfmetrics.registerFont(cidfonts.UnicodeCIDFont("HeiseiKakuGo-W5"))

# テンプレートの生成
pdf = canvas.Canvas("hello_world_test.pdf", pagesize=portrait(A4)) # "hello_world_test.pdf"という名前で縦書きA4サイズのキャンバスを生成
pdf.saveState() # キャンバスを初期化

width, height = A4   # 595px, 842px

# 文字の入力
pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(15*mm, height - 15*mm, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定
pdf.drawString(15*mm, height - 30*mm, 'こんにちは、世界!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

pdf.setFont('HeiseiKakuGo-W5', 18) # フォント名とフォントサイズを指定
pdf.drawString(100*mm, height / 2, 'Hello, world!') # 文字列の左下の座標x,y(原点は左下)および出力する文字列を指定

# 本文の作成
pdf.setFont('HeiseiKakuGo-W5', 12)
pdf.drawString(15*mm, height - 45*mm, '試しに長い文章を打ってみるとこうなります。はみ出してしまっていることがわかるでしょうか?勝手に折り返してほしいんですが…')
pdf.drawString(15*mm, height - 55*mm, 'しかも毎回文字打つ位置を指定してあげないといけないのがすごく手間です。')

pdf.save() # PDFファイルに保存

こんな感じで長い文章が切れてしまうので、毎回文章を区切って位置指定してとかやってられないですよね…

終わりに

今回一通りReportLabを使用したPDFファイルの作成方法について紹介しました。他のブログや記事とかでも今回の方法が主に紹介されておりますが、実はこの使い方はReportLabのほんのさわりの機能しか使えていないようです。
次回はもっと簡単にPDFファイルが作成できるようなReportLabの使い方を紹介したいと思います。今回上げた問題点はばっちり解決できますのでご安心を。

参考文献