Skip to content

Instantly share code, notes, and snippets.

@sobelk
Created April 7, 2010 20:03
Show Gist options
  • Save sobelk/359367 to your computer and use it in GitHub Desktop.
Save sobelk/359367 to your computer and use it in GitHub Desktop.

Revisions

  1. sobelk revised this gist Apr 8, 2010. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion latex.py
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,6 @@ def render(self, context):
    if not os.path.exists(os.path.join(workingdir, filebase + '.png')):
    latexpath = r'%s%s.tex' % (workingdir, filebase)

    # TODO: if file exists:
    latexfile = open(latexpath, 'w')
    latexfile.write('\n'.join(('% generated at: ' + str(datetime.now()),
    self.LATEX_HEADER,
  2. sobelk created this gist Apr 7, 2010.
    108 changes: 108 additions & 0 deletions latex.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,108 @@
    """
    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)

    # TODO: if file exists:
    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)