Last active
August 29, 2015 14:11
-
-
Save RobertSudwarts/ebf16daba7115689f799 to your computer and use it in GitHub Desktop.
generate PDFs on the fly (ie in a browser) using LaTeX, with Turbogears, mako templates and texcaller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Installation for debian based distros | |
You will of course need the tex library installed: | |
$ sudo apt-get install texlive | |
And SWIG is required for dealing with texcaller's 'C' wrapper. | |
$ sudo apt-get install swig | |
Download the texcaller package from github and 'make' the | |
python wrapper: | |
$ cd ~/mylib | |
$ git clone https://github.com/vog/texcaller.git | |
$ cd texcaller | |
$ make -C swig | |
$ cd python | |
$ python setup.py build_ext --inplace | |
We'll assume that you have a turbogears installation up and | |
running in a virtual environment (naturally!) so the virtualenv | |
needs to know where texcaller's python package lives (ie its | |
absolute path). The easiest way to accomplish this is to add a | |
.pth file to the virtualenv's 'site-packages' directory, thusly: | |
$ cd /../../virtualenvs/tg23/lib/python2.7/site-packages | |
$ echo "~/mylib/texcaller/python" > texcaller.pth | |
With the .pth in place, and with the virtualenv activated, | |
the following command should operate without error: | |
$ python -c "import texcaller" | |
We start with a document string to be parsed by mako | |
And see the bottom of this file for the Turbogears controller | |
which renders the final PDF. | |
""" | |
import texcaller | |
from tg import expose | |
from mako.template import Template | |
from myproject.lib.base import BaseController | |
document = r''' | |
\documentclass{scrartcl} | |
\usepackage[latin1]{inputenc} | |
\usepackage{tabularx} | |
\usepackage[letterpaper,top=3cm,bottom=-3cm,left=2cm,right=2cm]{geometry} | |
\usepackage{graphicx} | |
\begin{document} | |
\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont | |
\section{Simple Stuff} | |
\textbf{Hello ${name}!} | |
This \LaTeX-document has been created using a mako template. | |
\textit{This text will be italicised...} | |
In the next section we will display some subsections and render some | |
parameters passed from python. | |
\section{Control Structures} | |
\subsection{iterating over a simple list} | |
Here we demonstrate how mako can loop over a simple list to generate | |
some output -- look at the document string/template to see how a new line | |
character is used to cause a line break: | |
% for i, j in enumerate(simple_list): | |
${i} - ${j} ${'\n'} | |
% endfor | |
\subsection{generating a \LaTeX table} | |
Here we generate a tex table using a list of dicts. In order to get the | |
double backslash (required by the table markup), you use python's raw | |
text flag on the string ie r''. Notice also how the string concatenation | |
operates per line (ie per dict) followed by the double backslash which | |
is included (and this is the key point) in the \emph{raw} string. | |
\hfill \break | |
\hspace*{5cm} | |
\begin{tabular}{ lcc } | |
\hline | |
Fruit & eaten & uneaten ${r'\\'} | |
\hline | |
% for row in list_of_dicts: | |
${r'%(fruit)s & %(eaten)d & %(uneaten)d \\' % (row) } | |
% endfor | |
\hline | |
\end{tabular} | |
\end{document} | |
''' | |
class PDFController(BaseController): | |
'''Your root Turbogears controller will need to mount this eg: | |
pdf = PDFController() | |
And call this example with http://localhost:8080/pdf | |
''' | |
@expose(content_type="application/pdf") | |
def index(self): | |
# see texcaller's python specific documentation | |
# for why the .decode() is required. | |
# https://vog.github.io/texcaller/group__python.html | |
mytemplate = Template(document.decode('utf-8')) | |
list_of_dicts = [ | |
{'fruit': 'apples', 'eaten': 2, 'uneaten': 8}, | |
{'fruit': 'bananas', 'eaten': 4, 'uneaten': 10}, | |
{'fruit': 'oranges', 'eaten': 6, 'uneaten': 12}, | |
] | |
doc_params = dict( | |
name='World', | |
simple_list=['apples', 'bananas', 'oranges'], | |
list_of_dicts=list_of_dicts, | |
) | |
pdf, info = texcaller.convert( | |
mytemplate.render(**doc_params), 'LaTeX', 'PDF', 5 | |
) | |
return pdf |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment