1.1 --- a/actions/ExportPDF.py Fri Nov 01 01:45:00 2013 +0100
1.2 +++ b/actions/ExportPDF.py Fri Nov 01 15:21:36 2013 +0100
1.3 @@ -21,6 +21,7 @@
1.4 # Choose one value for the export mode.
1.5
1.6 PDF_EXPORT_MODE = "docbook"
1.7 +#PDF_EXPORT_MODE = "wkhtmltopdf"
1.8 #PDF_EXPORT_MODE = "htmldoc"
1.9
1.10 # Settings for "docbook" mode.
1.11 @@ -33,6 +34,11 @@
1.12
1.13 DOCBOOK_TO_FO_STYLESHEET = "docbook-xsl/fo/docbook.xsl"
1.14
1.15 +# Settings for "wkhtmltopdf" mode.
1.16 +
1.17 +XVFB_WRAPPER = "/usr/bin/xvfb-run"
1.18 +WKHTMLTOPDF_PROCESSOR = "/usr/bin/wkhtmltopdf"
1.19 +
1.20 # Settings for "htmldoc" mode.
1.21
1.22 HTMLDOC_PROCESSOR = "/usr/bin/htmldoc"
1.23 @@ -54,6 +60,12 @@
1.24 "2A0" : "Double A0"
1.25 }
1.26
1.27 +wkhtmltopdf_paper_sizes = [
1.28 + "A4", "Letter"
1.29 + ]
1.30 +
1.31 +wkhtmltopdf_paper_size_labels = {}
1.32 +
1.33 # NOTE: From the htmldoc man page.
1.34
1.35 htmldoc_paper_sizes = [
1.36 @@ -67,6 +79,18 @@
1.37 "universal" : "US universal"
1.38 }
1.39
1.40 +paper_sizes = {
1.41 + "docbook" : docbook_paper_sizes,
1.42 + "wkhtmltopdf" : wkhtmltopdf_paper_sizes,
1.43 + "htmldoc" : htmldoc_paper_sizes
1.44 + }
1.45 +
1.46 +paper_size_labels = {
1.47 + "docbook" : docbook_paper_size_labels,
1.48 + "wkhtmltopdf" : wkhtmltopdf_paper_size_labels,
1.49 + "htmldoc" : htmldoc_paper_size_labels
1.50 + }
1.51 +
1.52 class ExportPDF(ActionBase, ActionSupport):
1.53
1.54 "Export the current page as PDF."
1.55 @@ -74,16 +98,10 @@
1.56 mode = PDF_EXPORT_MODE
1.57
1.58 def _get_paper_sizes(self):
1.59 - if self.mode == "docbook":
1.60 - return docbook_paper_sizes
1.61 - else:
1.62 - return htmldoc_paper_sizes
1.63 + return paper_sizes.get(self.mode)
1.64
1.65 def _get_paper_size_labels(self):
1.66 - if self.mode == "docbook":
1.67 - return docbook_paper_size_labels
1.68 - else:
1.69 - return htmldoc_paper_size_labels
1.70 + return paper_size_labels.get(self.mode)
1.71
1.72 def get_form_html(self, buttons_html):
1.73
1.74 @@ -96,9 +114,9 @@
1.75 paper_size = form.get("paper-size", ["A4"])[0]
1.76
1.77 paper_size_options = []
1.78 - paper_size_labels = self._get_paper_size_labels()
1.79 + paper_size_labels = self._get_paper_size_labels() or {}
1.80
1.81 - for size in self._get_paper_sizes():
1.82 + for size in self._get_paper_sizes() or []:
1.83 paper_size_options.append('<option value="%s" %s>%s</option>' % (
1.84 escattr(size), self._get_selected(size, paper_size),
1.85 escape(_(paper_size_labels.get(size) or size))
1.86 @@ -132,23 +150,25 @@
1.87
1.88 paper_size = form.get("paper-size", [""])[0]
1.89
1.90 - if not paper_size in self._get_paper_sizes():
1.91 + if not paper_size in self._get_paper_sizes() or []:
1.92 return 0, _("A paper size must be chosen.")
1.93
1.94 if self.mode == "docbook":
1.95 return self._export_using_docbook(paper_size)
1.96 + elif self.mode == "wkhtmltopdf":
1.97 + return self._export_using_wkhtmltopdf(paper_size)
1.98 elif self.mode == "htmldoc":
1.99 return self._export_using_htmldoc(paper_size)
1.100 else:
1.101 return 0, _("The action must be configured to use a particular PDF generation tool.")
1.102
1.103 - def _export_using_htmldoc(self, paper_size):
1.104 + def _get_page_as_html(self):
1.105 +
1.106 + "Get the page in HTML format."
1.107
1.108 request = self.request
1.109 page = self.page
1.110
1.111 - # Get the page in HTML format.
1.112 -
1.113 fmt = getFormatterClass(request, "text_html")(request)
1.114 fmt.setPage(page)
1.115
1.116 @@ -168,41 +188,15 @@
1.117 </html>
1.118 """)
1.119
1.120 - # Send the HTML to the htmldoc processor.
1.121 -
1.122 - os.environ["HTMLDOC_NOCGI"] = "1"
1.123 -
1.124 - p = subprocess.Popen([
1.125 - HTMLDOC_PROCESSOR,
1.126 - "-t", "pdf", "--quiet", "--webpage",
1.127 - "--size", paper_size,
1.128 - "-"
1.129 - ],
1.130 - shell=False,
1.131 - stdin=subprocess.PIPE,
1.132 - stdout=subprocess.PIPE,
1.133 - stderr=subprocess.PIPE)
1.134 + return u"".join(page_as_html)
1.135
1.136 - writer = codecs.getwriter("utf-8")(p.stdin)
1.137 - writer.write(u"".join(page_as_html))
1.138 -
1.139 - out, err = p.communicate()
1.140 -
1.141 - retcode = p.wait()
1.142 + def _get_page_as_docbook(self):
1.143
1.144 - if retcode != 0:
1.145 - return 0, err
1.146 -
1.147 - self._write_pdf(out)
1.148 - return 1, None
1.149 -
1.150 - def _export_using_docbook(self, paper_size):
1.151 + "Get the page in DocBook format."
1.152
1.153 request = self.request
1.154 page = self.page
1.155
1.156 - # Get the page in DocBook format.
1.157 -
1.158 fmt = getFormatterClass(request, "text_docbook")(request)
1.159 fmt.setPage(page)
1.160
1.161 @@ -217,7 +211,75 @@
1.162 append(fmt.endContent())
1.163 append(fmt.endDocument())
1.164
1.165 - # Send the DocBook XML to the XSLT processor.
1.166 + return "".join(page_as_docbook)
1.167 +
1.168 + def _write_pdf_for_html(self, p, page_as_html):
1.169 +
1.170 + """
1.171 + Write to the process 'p', the HTML for the page, reading the PDF output
1.172 + from the process and writing it to the browser.
1.173 + """
1.174 +
1.175 + writer = codecs.getwriter("utf-8")(p.stdin)
1.176 + writer.write(page_as_html)
1.177 +
1.178 + out, err = p.communicate()
1.179 +
1.180 + retcode = p.wait()
1.181 +
1.182 + if retcode != 0:
1.183 + return 0, err
1.184 +
1.185 + self._write_pdf(out)
1.186 + return 1, None
1.187 +
1.188 + def _export_using_wkhtmltopdf(self, paper_size):
1.189 +
1.190 + """
1.191 + Send the page HTML to the processor, indicating the given 'paper_size'.
1.192 + """
1.193 +
1.194 + p = subprocess.Popen([
1.195 + XVFB_WRAPPER, "--",
1.196 + WKHTMLTOPDF_PROCESSOR,
1.197 + "--page-size", paper_size,
1.198 + "-",
1.199 + "-"
1.200 + ],
1.201 + shell=False,
1.202 + stdin=subprocess.PIPE,
1.203 + stdout=subprocess.PIPE,
1.204 + stderr=subprocess.PIPE)
1.205 +
1.206 + return self._write_pdf_for_html(p, self._get_page_as_html())
1.207 +
1.208 + def _export_using_htmldoc(self, paper_size):
1.209 +
1.210 + """
1.211 + Send the page HTML to the processor, indicating the given 'paper_size'.
1.212 + """
1.213 +
1.214 + os.environ["HTMLDOC_NOCGI"] = "1"
1.215 +
1.216 + p = subprocess.Popen([
1.217 + HTMLDOC_PROCESSOR,
1.218 + "-t", "pdf", "--quiet", "--webpage",
1.219 + "--size", paper_size,
1.220 + "-"
1.221 + ],
1.222 + shell=False,
1.223 + stdin=subprocess.PIPE,
1.224 + stdout=subprocess.PIPE,
1.225 + stderr=subprocess.PIPE)
1.226 +
1.227 + return self._write_pdf_for_html(p, self._get_page_as_html())
1.228 +
1.229 + def _export_using_docbook(self, paper_size):
1.230 +
1.231 + """
1.232 + Send the page DocBook XML to the processor, indicating the given
1.233 + 'paper_size'.
1.234 + """
1.235
1.236 p1 = subprocess.Popen([
1.237 XSLT_PROCESSOR,
1.238 @@ -231,7 +293,7 @@
1.239 stdout=subprocess.PIPE,
1.240 stderr=subprocess.PIPE)
1.241
1.242 - p1.stdin.write("".join(page_as_docbook))
1.243 + p1.stdin.write(self._get_page_as_docbook())
1.244 p1.stdin.close()
1.245
1.246 # Pipe the XML-FO output to the FO processor.