Created
April 7, 2010 20:03
-
-
Save sobelk/359367 to your computer and use it in GitHub Desktop.
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
""" | |
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 <img> 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 '<img src="%s" alt="%s" %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) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment