LoginSignup
0
0

More than 5 years have passed since last update.

サイボウズLiveでエクスポートしたデータをPDFに変換する [アップデート]

Posted at

背景

前回 サイボウズLiveからエクスポートしたCSVファイルをPDF化しました。

さて、いよいよサイボウズLiveサービス終了間近ということでいくつかアップデートしました。

目次機能

先頭に目次をつけるようにしました。また、目次をリンクにすることで記事にスムーズにジャンプできるようになりました。

変更点としては以下のとおりです。

BaseDocTemplate を継承したクラスの作成

Paragraphクラスである要素(=flowable)である場合、そのヘッダから目次のエントリを作成します。ちなみに、TOCEntrynotify することで自動的に目次のエントリに追加されるそうです。

 34 class DocTemplate(BaseDocTemplate):
 35     def __init__(self, filename, **kw):
 36         self.allowSplitting = 0
 37         BaseDocTemplate.__init__(self, filename, **kw)
 38         template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')])
 39         self.addPageTemplates(template)
 40 
 41     def afterFlowable(self, flowable):
 42         if flowable.__class__.__name__ == 'Paragraph':
 43             text = flowable.getPlainText()
 44             style = flowable.style.name
 45             if style == 'header':
 46                 self.notify('TOCEntry', (0, text, self.page, flowable._bookmark))

マニュアルに以下の記載があります。

Entries to the table of contents can be done either manually by calling the addEntry method on the
TableOfContents object or automatically by sending a 'TOCEntry' notification in the
afterFlowable method of the DocTemplate you are using.

目次の作成

最初に目次(=TOC: Table Of Contents)の作成コードを追加しただけです。

338 def gen_pdf(generator, output, toc=True):
339     addMapping(DEFAULT_FONT, 1, 1, DEFAULT_FONT)
340 
341     story = []
342 
343     if toc:
344         title_style = ParagraphStyle(
345             fontName=DEFAULT_FONT,
346             fontSize=15,
347             name='TOC',
348             spaceAfter=10
349         )
350         story.append(Paragraph('目次', title_style))
351 
352         toc = TableOfContents()
353         toc.levelStyles = [
354             ParagraphStyle(
355                 fontName=DEFAULT_FONT,
356                 fontSize=8,
357                 name='body',
358                 spaceAfter=4,
359                 justifyBreaks=1
360             )
361         ]
362 
363         story.append(toc)
364         story.append(PageBreak())
365 
366     story.extend(generator.convert())
367 
368     doc = DocTemplate(output)
369     pdfmetrics.registerFont(TTFont(DEFAULT_FONT, DEFAULT_FONT_FILE))
370     doc.multiBuild(story)

リンクの作成

まず、記事を一意に識別できる名前を作ります。後で考えたら記事のIDで良かったのですが、今回はタイトルの文字列をxxHashしたものを識別名としました。

DocTemplateクラス内のself.notifyですが、第二引数のタプル(0, text, self.page, flowable._bookmark)の4要素目に先程の識別名を代入することでリンクとして動作します。ただし、この識別名を渡す手段が特に用意されていないので_bookmarkのような適当なメンバを作成して代入してます(111行目)。

また、実際のジャンプ先に<a>タグを設定する必要があるようです。そこで、この識別名をname属性に持つ<a>タグをheaderに入れます(108行目)。

101     def convert(self):
102         import xxhash
103         story = []
104         for board in self.boards:
105             title = '{} [{}]'.format(board.title, board.id)
106             creator = '{} ({})'.format(board.creator, board.create_time)
107             digest = xxhash.xxh32_hexdigest(title)
108             header = '{} / {} <a name={} />'.format(title, creator, digest)
109 
110             hp = Paragraph(header, self.header_style)
111             hp._bookmark = digest
112             story.append(hp)
113             story.append(Paragraph(board.body, self.body_style))
114             story.extend(CommentGenerator(board.comments).convert())
115             story.append(PageBreak())
116 
117         return story

目次の作り方はこちらのコードが参考になります。

見た目の変更

以下の変更を行いました。

  • 作成日順にソート(CSVは最終更新日順に並んでいるようです)
  • トピックのタイトルを矩形、本文を網掛けで装飾
  • コメントの改行が正しく表示されない問題の修正

使い方

シンプル

$ python generate.py live_board.csv board.pdf

作成日を指定(2018年の記事だけをPDF化したい等の用途)

python generate.py -f 2018/01/01 -t 2019/01/01 live_board.csv board.pdf
0
0
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
0
0