[[ともっくす alloc] init]

ともっくすの雑多な日記と技術的なメモ

PythonでPDFを生成したい そしてサイコロを作りたい

研究室に毎日行っているわけだが,夜もいるので,どうしても夕食は外食となる.

嬉しいことに,我が大学の近くには食事するところがたくさんある.

しかし,長年大学に通っていると,どこに行くか決めづらくなる.

で,最近導入されたのが「食事する場所を決めるサイコロ(紙製組立型)」.

各面に食事する場所が載っていて,サイコロを振って,ランダムに決めるという優れものとなっている.

素晴らしい先輩が作ってくださった.

それを使っていて,サイコロの面に色んなことを載せて,ランダムに決められるのって楽しいなって思った.

んで,各面に載せる語句を指定するだけで,そのサイコロの展開図の載ったpdfを生成するプログラムでも作りたいなーって思った.


というわけで,作ってみた.


まあ,Pythonを使ったpdfの生成なんてしたことなかったし,それをまとめてみる.

reportlab

PythonでPDFを扱えるようにするためのライブラリとして,reportlabがある.
ReportLab: Open Source Python Libraries for PDF creation - ReportLab.com

環境構築

仮想環境

まず,virtualenvを使って,仮想環境を作る.
(別にこんなことしなくてもできる)

環境名はenv-pdfで.

$ mkvirtualenv env-pdf

virtualenvとかの使い方はここ.
> Pythonの仮想環境 virtualenvとvirtualenvwrapper - [[ともっくす alloc] init]

reportlabのインストール

pipを使うだけ.

env-pdfがアクティベートされていることを確認して,

$ pip install reportlab

virtualenvを使わない場合は,

$ sudo pip install reportlab

でいいかも.

以上.

使ってみる

とりあえず,サンプルとして書いたコードはこんな感じ.

# -*- coding: utf-8 -*-

from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
import reportlab.lib.colors as color


def make(filename="pdftest"):
    pdf_canvas = set_info(filename)
    print_string(pdf_canvas)
    print_figure(pdf_canvas)
    print_line(pdf_canvas)
    pdf_canvas.save()


# 初期設定
def set_info(filename):
    pdf_canvas = canvas.Canvas("./{0}.pdf".format(filename), bottomup=False)  # 原点は左上
        
    pdf_canvas.setAuthor("ともっくす")
    pdf_canvas.setTitle("pythonを使ってpdf_canvasを生成する")
    pdf_canvas.setSubject("reportlab")

    return pdf_canvas


# 文字
def print_string(pdf_canvas):
    # フォントを登録する
    pdfmetrics.registerFont(UnicodeCIDFont("HeiseiKakuGo-W5"))
    pdfmetrics.registerFont(UnicodeCIDFont("HeiseiMin-W3"))

    # ゴシック体をサイズ15で
    pdf_canvas.setFont("HeiseiKakuGo-W5", 15)
    pdf_canvas.drawString(50, 50, "ゴシック体をサイズ15で")

    # 明朝体をサイズ30で
    pdf_canvas.setFont("HeiseiMin-W3", 30)
    pdf_canvas.drawString(300, 100, "明朝体をサイズ30で")


# 図形
def print_figure(pdf_canvas):
    # 枠線のみの四角
    pdf_canvas.rect(50, 150, 200, 250)

    # 青色の円
    pdf_canvas.setFillColor(color.blue)
    pdf_canvas.circle(400, 350, 50, stroke=False, fill=True)


# 線
def print_line(pdf_canvas):
    # 普通の線
    pdf_canvas.line(50, 450, 500, 450)

    # 赤い太い線
    pdf_canvas.setStrokeColor(color.red)
    pdf_canvas.setLineWidth(10)
    pdf_canvas.line(100, 500, 550, 500)

    # 破線
    pdf_canvas.setStrokeColor(color.black)
    pdf_canvas.setLineWidth(5)
    pdf_canvas.setDash([2, 8, 5, 10])
    pdf_canvas.line(150, 550, 600, 550)

    # 複数の線
    pdf_canvas.setLineWidth(1)
    pdf_canvas.setDash([])
    lines = [(100, 650, 200, 750), (200, 750, 300, 650), (300, 650, 300, 750), (100, 700, 400, 700)]
    pdf_canvas.lines(lines)


if __name__ == '__main__':
    make()

で,これを実行すると,

f:id:o_tomox:20130722213529p:plain

いい感じ.

初期設定(set_info)

まず,Canvasを使って,pdf生成のためのキャンバス(?)を生成する.

このときに,ファイル名も与える.

で,図形を描いたりするんだけど,デフォルトでは原点が左下になってる.

普通はこれでいいかもしれなけど,原点を左上にしてほしい人も多いと思う.(自分も)

そのために,bottomup=Falseを指定する.


さらに,生成されるpdfファイルに色んな情報を付加することもできる.

上みたいに設定することで,プロパティを見ると,こうなってる.(Macの場合)
f:id:o_tomox:20130722214126p:plain

おー.

文字(print_string)

日本語を使う場合にはフォントを登録する必要がある.

デフォルトで用意されているのは,ゴシック体のHeiseiKakuGo-W5と明朝体のHeiseiMin-W3だけ.

他にもどうにかしたらできるっぽいけど,やっていない.

で,setFont(文字フォント, 文字サイズ)を使って,フォントとサイズを指定する.

そして,drawString(x, y, 表示したい文字列)で,文字列を描画できる.

xは文字の左端,yは文字の下端になるので,注意が必要.
drawString(0, 0, "あいう")とかしても,見えない.

図形(print_figure)

図形としては,矩形と円と楕円が描画できる,はず.


矩形は,rect(x, y, 幅, 高さ)で描画する.

原点を左上にしている場合には,xとyは矩形の左上の座標を表す.
(原点が左下の場合には,xとyは矩形の左下の座標になる*1


円は,circle(x, y, 半径)で描画する.

円の中心の座標がxとyに対応する.


各メソッドには,strokeとfillという引数を与えることができる.

strokeは枠線を描くかどうかを表すフラグで,Falseで枠線を描画しない設定にできる.

fillはその図形を塗りつぶすかどうかを表すフラグで,Trueで設定された色で塗りつぶすことができる.

塗りつぶす色はsetFillColor(色)で指定できる.

線(print_line)

直線は,line(x_start, y_start, x_end, y_end)で描画できる.

線の色はsetStrokeColor(色)で指定でき,(図形の枠線も同じ)
線の太さはsetLineWidth(太さ)で指定できる.

また,破線は,setDash(間隔のリスト)で指定できる.

さらに,線の座標をリストにして,lines(リスト)に渡すと,一括で描画することもできる.



こんな感じだろうか.

他にも色々できるっぽい.

図形の描画じゃなくて,それっぽい文書の作成とか.

でも,如何せん,日本語の情報が少なくてツラい.


サイコロのコードとか実物?

そんなもの載せたくない.

*1:文字の場合は原点の位置に関係なく文字の左下が基準になるのに,矩形の場合は原点の位置によって基準が変わるのはなぜだ