""" Django LaTeX custom template tag for equations (using amsmath). Creates a .png in the project media directory and returns an img tag that references it. Usage: {% latex %} x=\frac{-b \pm \sqrt {b^2-4ac}}{2a} {% endlatex %} Requirements: LaTeX (http://www.latex-project.org/ftp.html) dvipng (http://savannah.nongnu.org/projects/dvipng/) Thanks to Kjell Magne Fauske (http://www.fauskes.net/nb/htmleqII/) for outlining the method. """ from django import template register = template.Library() class LaTeXNode(template.Node): # directory to append to MEDIA_ROOT and MEDIA_URL, terminate with / OUTPUT_DIR = 'image/latex/' # class name to assign to generated tag IMG_CLASS_NAME = 'latex' LATEX_HEADER = ''' \\documentclass{article} \\usepackage{amsmath} \\usepackage{amsthm} \\usepackage{amssymb} \\usepackage{bm} \\pagestyle{empty} \\begin{document} ''' LATEX_FOOTER = ''' \\end{document} ''' def __init__(self, nodelist, label=None): self.nodelist = nodelist self.label = label def render(self, context): import subprocess import os from datetime import datetime from hashlib import md5 from django.conf import settings latex = self.nodelist.render(context) filebase = md5(latex).hexdigest() workingdir = os.path.join(settings.MEDIA_ROOT, self.OUTPUT_DIR) if not os.path.exists(os.path.join(workingdir, filebase + '.png')): latexpath = r'%s%s.tex' % (workingdir, filebase) latexfile = open(latexpath, 'w') latexfile.write('\n'.join(('% generated at: ' + str(datetime.now()), self.LATEX_HEADER, '$%s$' % latex, # delimit equation with $ self.LATEX_FOOTER))) latexfile.close() old_workingdir = os.getcwd() os.chdir(workingdir) latex_exitcode = subprocess.call((r'latex', filebase + '.tex')) dvipng_exitcode = subprocess.call((r'dvipng', '-o', filebase + '.png', '-pp', '1', # only page one '-T', 'tight', '-x', '1600', # scale filebase + '.dvi')) if latex_exitcode or dvipng_exitcode: # TODO: There is room for better error reporting here, # but I'm happy to fail silently and leave the temp # files behind for debugging. return latex else: os.unlink(filebase + '.tex') os.unlink(filebase + '.log') os.unlink(filebase + '.aux') os.unlink(filebase + '.dvi') os.chdir(old_workingdir) return '%s' % ( settings.MEDIA_URL + self.OUTPUT_DIR + filebase + '.png', latex, self.IMG_CLASS_NAME and 'class="%s" ' % self.IMG_CLASS_NAME or '') def latex(parser, token): nodelist = parser.parse(('endlatex',)) parser.delete_first_token() parts = token.contents.split() if len(parts) == 1: return LaTeXNode(nodelist) else: raise template.TemplateSyntaxError( "latex tag does not accept parameters, got '%s'" % ( ' '.join(parts[1:]))) register.tag('latex', latex)