LoginSignup
21
24

More than 3 years have passed since last update.

お前らのReportLabの使い方は間違っている

Last updated at Posted at 2020-12-09

TL; DR

もっとFlowableオブジェクト使おう。
テキストは折り返してくれるし、スタイル指定もしやすいよ!
表とかも書きやすいよ!
Frame使ったら、複雑な組版もできるよ!

煽り記事風タイトルですが、別にdrawStringとかが適した場面もあるとは思います。

ReportLabとは

ReportLab

pythonでPDFを出力するためのライブラリです。
有料版もあるけど、無償版でも十分使えます。

日本語情報が少ない?

サンプルコードはcanvas.drawStringで終わっている率が高い。
そもそも、canvasのメソッド(drawPath、rect,gridなど)だけで描きたいものが描ききれるのか。
SimpleDocTemplateを使用している例が少ないので、みんな使いこなしていないのではないかと。
BaseDocTemplateの例はもっと見つからない。

DocTemplateを使うと何がいい?

Flowableオブジェクトのリストを渡してビルドすると、いい感じに並べてくれる。
drawStringとかrectとかだと、座標指定なので、
描画したもの同士が重ならないようにするには、自前で計算する必要がある。
(重ねたい場合もあるけど)

Flowableオブジェクトの例

  • Paragraph
    • text 段落
  • Image
    • 画像
  • Table
    • 表 タイトル行だけ次のページにも出すとか柔軟な設定も可能。
  • Spacer
    • スペース

BaseDocTemplate

SimpleDocTemplateはFlowableを並べるだけだけど、
BaseDocTemplateならFrameを使って、複雑な組版も可能。
連番とか、少しずつ違うラベルを大量に印刷する時にも活躍することも。
(差し込み印刷? 余白設定をぶっ壊す人さえいなければ......)

ただし、日本語の禁則処理はできない。

reportlab.png

from reportlab.platypus import BaseDocTemplate, PageTemplate
from reportlab.platypus import Paragraph, PageBreak, FrameBreak
from reportlab.platypus.flowables import Spacer
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.pagesizes import A4, mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import cidfonts
from reportlab.platypus.frames import Frame
def main():
    pdfmetrics.registerFont(cidfonts.UnicodeCIDFont("HeiseiMin-W3"))

    buf = "/tmp/test.pdf"

    doc = BaseDocTemplate(buf, 
        title="本当のreportlab",
        pagesize=(200*mm, 200*mm),
        )

    show = 1 #Frameの枠を表示
    frames = [
            Frame(25 * mm, 120*mm, 150*mm, 50*mm, showBoundary=0),
            Frame(10 * mm, 30*mm, 70*mm, 80*mm, showBoundary=show),
            Frame(110 * mm, 50*mm, 75*mm, 60*mm, showBoundary=show),
        ]

    page_template = PageTemplate("frames", frames=frames)
    doc.addPageTemplates(page_template)


    style_dict ={
        "name":"nomarl",
        "fontName":"HeiseiMin-W3",
        "fontSize":20,
        "leading":20,
        "firstLineIndent":20,
        }
    style = ParagraphStyle(**style_dict)

    flowables = []

    space = Spacer(10*mm, 10*mm)

    para = Paragraph("こんなものは、reportlabではない!!", style)
    flowables.append(para)
    flowables.append(space)
    para = Paragraph("本当のreportlabをお見せします。", style)
    flowables.append(para)
    flowables.append(space)
    para = Paragraph("次のページに来てください", style)
    flowables.append(para)

    #改ページ
    flowables.append(PageBreak()) 

    para = Paragraph("<span backcolor=yellow>フーレム1</span>", style)
    flowables.append(para)
    para = Paragraph("Paragraphを使うことで長い文章を自動で折り返してくれます。さらにはみ出せば次のページに進みます。", style)
    flowables.append(para)
    para = Paragraph("ちゃんと続きの高さから次のParagraphを描画してくれます。", style)
    flowables.append(para)
    para = Paragraph("Frameを使えば、はみ出した分は次のフレームまたはページへ自動で進みます。", style)
    flowables.append(para)
    para = Paragraph("Frameを使うことで、段組みのような複雑なレイアウトを表現できます。", style)
    flowables.append(para)

    #次のフレームへ
    flowables.append(FrameBreak())

    para = Paragraph("<span color=red>フレーム3</span>", style)
    flowables.append(para)
    para = Paragraph("FrameBreakを使えば次のFrameに進みます。", style)
    flowables.append(para)
    para = Paragraph("PageBreakを使えば次のPageに進みます。", style)
    flowables.append(para)


    doc.multiBuild(flowables)

if __name__ == '__main__':
    main()
21
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
24