概要
PyFPDFを使ってHTMLからPDFを生成する。
バージョン情報
- Python 3.7.6
- fpdf==1.7.2
インストール
$ pip install fpdf
簡易なPDFの作成
まずは公式サイトの説明にもあるミニマムなコードでPDFファイルを作成してみる。
from fpdf import FPDF pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) pdf.cell(40, 10, 'Hello World!') pdf.output('tuto1.pdf', 'F')
set_fontとset_font_size
続いてフォントサイズを変えながら出力してみる。
set_fontのパラメータはこんな感じ。
set_font(family, style='', size=0)
先ほど実行した例文のBはbold。その他に I(Italic)と U(Underline)が指定できる。
サイズだけを変えたい場合は set_font_size を使う。
試しにUnderlineを指定して、フォントサイズを16, 24, 32と変えながらhello worldを表示してみる。
pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'U', 16) for font_size in [16, 24, 32]: pdf.set_font_size(font_size) pdf.ln() # line break pdf.cell(100, font_size / 2, 'Hello World!') pdf.output('tuto1.pdf', 'F')
途中で入っている pdf.ln() はline breakで、これを入れないとセルが右に並ぶ形になる。
日本語フォントの指定
上述のset_fontで指定しているfamilyのArialは日本語には対応していないので、表示するテキストに日本を入れると下記のようなエラーになる。
UnicodeEncodeError: 'latin-1' codec can't encode character '\u3042' in position 95: ordinal not in range(256)
フォントをaddして日本語を表示してみる。
Linuxの例だとまずはfc-listでフォントファイルのパスを確認。
$ fc-list
出力された中から適当なフォントを選んでadd_fontして、set_fontする。
add_fontの内容は下記。
add_font(family, style='', fname='', uni=False)
familyに適当な名前を指定して、fnameにフォントのパスを入れ、日本語の場合はuni=Trueを指定しておく。
pdf = FPDF() pdf.add_page() # fontをaddする font_path = '/usr/share/fonts/truetype/fonts-japanese-gothic.ttf' pdf.add_font('gothic', fname=font_path, uni=True) # 上で登録したfontをsetする pdf.set_font('gothic') pdf.cell(10, 10, 'あいうえお') pdf.output('tuto1.pdf', 'F')
set_xy
set_xyでポジションを指定して任意の場所にテキストを表示してみる。
pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) pdf.set_xy(30, 50) pdf.cell(50, 10, '30x50') pdf.set_xy(100, 25) pdf.cell(50, 10, '100x25') pdf.output('tuto1.pdf', 'F')
line
lineで線を引いてみる。
pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) # テキストの表示 pdf.set_xy(30, 50) pdf.cell(50, 10, '30x50') # これに被るような位置に線を表示 pdf.line(20, 40, 60, 70) pdf.output('tuto1.pdf', 'F')
lineの引数はそれぞれx1, y1, x2, y2。
画像を表示してみる
pdf.imageで画像を表示できる。
image(name, x=None, y=None, w=0, h=0, type='', link='')
pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) # 画像の表示 pdf.image('dog.jpg', x=10, y=20, w=60, h=60) # 上からテキストを表示 pdf.set_xy(30, 20) pdf.cell(10, 10, 'pretty dog') pdf.output('tuto1.pdf', 'F')
pdf.imageへの引数はファイル名かURLのみ指定できるようで、bytesやio.BytesIOなどで引数を渡すことはできない。
一旦、tempfileに保存して処理をするしか無いのだろうか。
下記はNamedTemporaryFileでwithスコープを外れたらファイルが消える形で一時ファイルを書くケース。
import tempfile pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) # imageをbyesで手元に持っていたとする with open('dog.jpg', 'rb') as fp: image_data = fp.read() with tempfile.NamedTemporaryFile() as temp: # tempfileに一度書き込む temp.write(image_data) temp.flush() # 画像を読み込む pdf.image('dog.jpg', x=10, y=20, w=60, h=60) # 上からテキストを表示 pdf.set_xy(30, 20) pdf.cell(10, 10, 'pretty dog') pdf.output('tuto1.pdf', 'F')
HTMLからPDFに変換
HTMLをPDFに変換する場合は、HTMLMixinを継承したクラスを作り、write_htmlを呼び出す。
from fpdf import FPDF, HTMLMixin class HtmlFPDF(FPDF, HTMLMixin): pass html = '<html><h1>Hello World!</h1></html>' pdf = HtmlFPDF() pdf.add_page() pdf.write_html(html) pdf.output('tuto1.pdf', 'F')
残念な点として、PyFPDFではCSSには対応していないらしい。HTML/CSSからPDFを作りたい場合はxhtml2pdf等の他のライブラリを検討する必要がある。
改定履歴
Author: Masato Watanabe, Date: 2020-03-07, 記事投稿