1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/actions/ExportPDF.py Thu Oct 31 23:46:00 2013 +0100
1.3 @@ -0,0 +1,180 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - Export as PDF action
1.7 +
1.8 + @copyright: 2013 by Paul Boddie <paul@boddie.org.uk>
1.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.10 +"""
1.11 +
1.12 +from MoinMoin.action import ActionBase
1.13 +from MoinMoin.wikiutil import escape
1.14 +from MoinSupport import ActionSupport, escattr, getFormatterClass, formatText, get_send_headers
1.15 +from os.path import join
1.16 +import subprocess
1.17 +
1.18 +__version__ = "0.1"
1.19 +
1.20 +Dependencies = ['page']
1.21 +
1.22 +# Configuration settings.
1.23 +
1.24 +XSLT_PROCESSOR = "/usr/bin/xsltproc"
1.25 +FO_PROCESSOR = "/usr/bin/fop"
1.26 +DOCBOOK_STYLESHEET_BASE = "/usr/share/xml/docbook/stylesheet"
1.27 +
1.28 +# Tool settings.
1.29 +
1.30 +DOCBOOK_TO_FO_STYLESHEET = "docbook-xsl/fo/docbook.xsl"
1.31 +
1.32 +# NOTE: From docbook-xsl/fo/param.xsl.
1.33 +
1.34 +paper_sizes = [
1.35 + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10",
1.36 + "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B10",
1.37 + "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10",
1.38 + "A4landscape", "USletter", "USlandscape", "4A0", "2A0",
1.39 + ]
1.40 +
1.41 +paper_size_labels = {
1.42 + "A4landscape" : "A4 landscape",
1.43 + "USletter" : "US letter",
1.44 + "USlandscape" : "US landscape",
1.45 + "4A0" : "Quadruple A0",
1.46 + "2A0" : "Double A0"
1.47 + }
1.48 +
1.49 +class ExportPDF(ActionBase, ActionSupport):
1.50 +
1.51 + "Export the current page as PDF."
1.52 +
1.53 + def get_form_html(self, buttons_html):
1.54 +
1.55 + "Return the action's form incorporating the 'buttons_html'."
1.56 +
1.57 + _ = self._
1.58 + request = self.request
1.59 + form = self.get_form()
1.60 +
1.61 + paper_size = form.get("paper-size", ["A4"])[0]
1.62 +
1.63 + paper_size_options = []
1.64 +
1.65 + for size in paper_sizes:
1.66 + paper_size_options.append('<option value="%s" %s>%s</option>' % (
1.67 + escattr(size), self._get_selected(size, paper_size),
1.68 + escape(_(paper_size_labels.get(size) or size))
1.69 + ))
1.70 +
1.71 + d = {
1.72 + "paper_size_label" : escape(_("Paper size")),
1.73 + "paper_size_options" : u"".join(paper_size_options),
1.74 + "buttons_html" : buttons_html,
1.75 + }
1.76 +
1.77 + return u"""\
1.78 +<table>
1.79 + <tr>
1.80 + <td class="label"><label>%(paper_size_label)s</label></td>
1.81 + <td><select name="paper-size">%(paper_size_options)s</select></td>
1.82 + </tr>
1.83 + <tr>
1.84 + <td></td>
1.85 + <td class="buttons">%(buttons_html)s</td>
1.86 + </tr>
1.87 +</table>
1.88 +""" % d
1.89 +
1.90 + def do_action(self):
1.91 +
1.92 + "Attempt to post a comment."
1.93 +
1.94 + _ = self._
1.95 + request = self.request
1.96 + form = self.get_form()
1.97 + page = self.page
1.98 +
1.99 + paper_size = form.get("paper-size", [""])[0]
1.100 +
1.101 + if not paper_size in paper_sizes:
1.102 + return 0, _("A paper size must be chosen.")
1.103 +
1.104 + # Get the page in DocBook format.
1.105 +
1.106 + fmt = getFormatterClass(request, "text_docbook")(request)
1.107 + fmt.setPage(page)
1.108 +
1.109 + # The DocBook formatter needs to pretend a full document is being made.
1.110 +
1.111 + page_as_docbook = []
1.112 + append = page_as_docbook.append
1.113 +
1.114 + append(fmt.startDocument(page.page_name))
1.115 + append(fmt.startContent())
1.116 + append(formatText(page.get_raw_body(), request, fmt, inhibit_p=False).encode("utf-8"))
1.117 + append(fmt.endContent())
1.118 + append(fmt.endDocument())
1.119 +
1.120 + # Send the DocBook XML to the XSLT processor.
1.121 +
1.122 + p1 = subprocess.Popen([
1.123 + XSLT_PROCESSOR,
1.124 + "-stringparam", "fop1.extensions", "1",
1.125 + "--stringparam", "paper.type", paper_size,
1.126 + join(DOCBOOK_STYLESHEET_BASE, DOCBOOK_TO_FO_STYLESHEET),
1.127 + "-"
1.128 + ],
1.129 + shell=False,
1.130 + stdin=subprocess.PIPE,
1.131 + stdout=subprocess.PIPE,
1.132 + stderr=subprocess.PIPE)
1.133 +
1.134 + p1.stdin.write("".join(page_as_docbook))
1.135 + p1.stdin.close()
1.136 +
1.137 + # Pipe the XML-FO output to the FO processor.
1.138 +
1.139 + p2 = subprocess.Popen([
1.140 + FO_PROCESSOR,
1.141 + "-fo", "-",
1.142 + "-pdf", "-",
1.143 + ],
1.144 + shell=False,
1.145 + stdin=p1.stdout,
1.146 + stdout=subprocess.PIPE,
1.147 + stderr=subprocess.PIPE)
1.148 +
1.149 + out, err = p2.communicate()
1.150 +
1.151 + retcode = p1.wait()
1.152 +
1.153 + if retcode != 0:
1.154 + return 0, err
1.155 +
1.156 + retcode = p2.wait()
1.157 +
1.158 + if retcode != 0:
1.159 + return 0, err
1.160 +
1.161 + send_headers = get_send_headers(request)
1.162 + headers = ["Content-Type: application/pdf"]
1.163 + send_headers(headers)
1.164 + request.write(out)
1.165 +
1.166 + return 1, None
1.167 +
1.168 + def render_success(self, msg, msgtype=None):
1.169 +
1.170 + """
1.171 + Render neither 'msg' nor 'msgtype' since a resource has already been
1.172 + produced.
1.173 + NOTE: msgtype is optional because MoinMoin 1.5.x does not support it.
1.174 + """
1.175 +
1.176 + pass
1.177 +
1.178 +# Action invocation function.
1.179 +
1.180 +def execute(pagename, request):
1.181 + ExportPDF(pagename, request).render()
1.182 +
1.183 +# vim: tabstop=4 expandtab shiftwidth=4