reportlab で PDF作成する時のページ番号 Page x of total の出力

Python reportlab でPDF作成で、
  ”ページ番号 of 総ページ数"
を出力する場合、 reportlabplatypus 機能を
使わないで実現するのは、総ページ数算出の為に、Canvas の showPage() 実行をカウント
または、その予測計算をしなくてはならず、そういう処理ロジックをコーディングする
のはつらい。(書けないわけじゃないけど、酷くてあんまりだ。。。)

かと言って、platypus  の Paragraph 配列に出力するものを突っ込んで、
reportlab で決められた SimpleDocTemplate のマージン等囲まれ、
決められた中でしか配置できないのも自由度が失われて嫌だ。

ページ番号 出力は、DocTemplate の build 引数で指定する
canvasmaker で ページ番号 を書きだすクラスを
指定するのだが、それだけを活かして、他のテンプレート
(既に存在するPDFをテンプレートにする方法)でPDFを作成する。

ページ番号作成クラス、開発ターゲットプロジェクト用に1つ用意しておく。
  pagenumCanvas.py  import して利用する

# -*- coding: UTF-8 -*-
#   pagenumCanvas.py : reportlab DocTemplate build canvasmaker=PageNumCanvas
#
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm

class PageNumCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        canvas.Canvas.__init__(self, *args, **kwargs)
        self.pages = []
    def showPage(self):
        self.pages.append(dict(self.__dict__))
        self._startPage()
    def save(self):
        page_count = len(self.pages)
        for page in self.pages:
            self.__dict__.update(page)
            self.draw_page_number(page_count)

            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)
    def draw_page_number(self, page_count):
        page = "Page %s of %s" % (self._pageNumber, page_count)
        self.setFont("Helvetica", 10)
        self.drawRightString(195 * mm, 272 * mm, page)

↑は。以下を参考にさせてもらった。ほとんどそのままだが。。。
http://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/
http://code.activestate.com/recipes/546511-page-x-of-y-with-reportlab/
http://code.activestate.com/recipes/576832/

この pagenumCanvas.py と同じディレクトリで以下、サンプルを用意する。

# -*- coding: UTF-8 -*-
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl

from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from reportlab.pdfbase import pdfmetrics
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
import reportlab.rl_config

from pagenumCanvas import PageNumCanvas

import webbrowser

pdfmetrics.registerFont(UnicodeCIDFont('HeiseiKakuGo-W5'))
center_w = reportlab.rl_config.defaultPageSize[0] / 2.0
center_h = reportlab.rl_config.defaultPageSize[1] / 2.0

# テンプレート読込
page = PdfReader('template.pdf', decompress=False).pages
pp = pagexobj(page[0])

def laterPages(canvas, doc):
    # サンプルなので無理やりループする。(目的の印字処理)
    for i in range(4):
        if i > 0: canvas.showPage()
        canvas.doForm(makerl(canvas, pp))
        canvas.saveState()
        canvas.setFont("HeiseiKakuGo-W5", 9)
        #----- 目的の出力 -----
        canvas.drawCentredString(center_w, center_h, "あいう テスト")
        #
        canvas.restoreState()
def run():
    outfile = 'res.pdf'
    doc = SimpleDocTemplate(outfile)
    doc.build([Paragraph("", getSampleStyleSheet()['Normal'])]
              , onFirstPage=laterPages
              , onLaterPages=laterPages
              , canvasmaker=PageNumCanvas)
    # 結果をブラウザ表示
    webbrowser.open(outfile)
run()

↑ Paragraph の配列を SimpleDocTemplate の build に渡すのだが
、ここで敢えて空文字を1要素だけ渡す。
onFirstPage も、onLaterPages も同じメソッドを指定する!
canvasmaker で、pagenumCanvas.py の PageNumCanvas を指定する!
onFirstPage 、onLaterPages で指定するメソッド laterPages において、
・採用したいページテンプレートを適用させる。
・出力したいだけ任意に印字処理を実行する。
  → Canvasオブジェクトで draw Xxxx の処理を書ける。
・改ページも任意に実行することで、自動的に
  PageNumCanvas がページカウント処理してくれる。

書いてみるとかなり強引だけど、reportlab の platypus
じっくり読んでる暇が無い時は、これでも良いのでないだろうか。