Skip to content

Instantly share code, notes, and snippets.

@dzhuang
Forked from sobelk/latex.py
Created April 25, 2016 15:43
Show Gist options
  • Save dzhuang/7400195b14e373eddb298627fb406018 to your computer and use it in GitHub Desktop.
Save dzhuang/7400195b14e373eddb298627fb406018 to your computer and use it in GitHub Desktop.
"""
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