/ docs / src / html-latex-images
html-latex-images
 1  #!/usr/bin/env python
 2  # vim: sts=4 sw=4 et
 3  
 4  import os, shutil, sys, subprocess
 5  import tempfile, hashlib
 6  import lxml.etree as ET
 7  
 8  tmpdir = None
 9  
10  cachedir = os.environ.get('HTML_LATEX_CACHE', './cache')
11  
12  nsmap = {'xhtml':"http://www.w3.org/1999/xhtml"}
13  
14  latex_header = r"""
15  \documentclass{article}
16  \usepackage[mathletters]{ucs}
17  \usepackage[utf8x]{inputenc}
18  %\usepackage[T2A]{fontenc}
19  %\usepackage[english,russian]{babel}
20  \usepackage{euscript}
21  \usepackage{type1cm}
22  \usepackage{amssymb}
23  \usepackage{amsmath}
24  \usepackage{ulem}
25  \usepackage{mathrsfs}
26  \begin{document}
27  \thispagestyle{empty}
28  """
29  
30  latex_footer = r"""
31  \end{document}
32  """
33  
34  latex_cmd = "latex -interaction nonstopmode ./file.tex".split()
35  dvipng_cmd = "dvipng -q -D 148 -T tight -pp 1 --noghostscript file.dvi -o file.png".split() 
36  
37  def build_img(fn, e, block=False):
38      txt = e.text.strip()
39      txt = txt.replace('&gt;', '>').replace('&lt;', '<').replace('&amp;', '&') # XML escapes
40      txt = txt.replace('\\[', '[').replace('\\]', ']') # Asciidoc escapes
41      md5 = hashlib.md5(txt.encode('utf-8')).hexdigest()
42      img = md5 + ".png"
43      fullimg = os.path.join(cachedir, img)
44      if not os.path.exists(fullimg):
45          latex(txt, block)
46          os.rename(os.path.join(tmpdir, 'file.png'), fullimg)
47      shutil.copy2(fullimg, os.path.join(os.path.dirname(fn), img))
48      node = ET.Element('img', attrib={'class':'latexmath'}, id=md5, src=img, title=txt)
49      e.getparent().replace(e, node)
50      return 1
51      
52  def latex(txt, block=False):
53      if block:
54          if not txt.startswith('$$'): txt = '$$' + txt
55          if not txt.endswith('$$'): txt = txt + '$$'
56      else:
57          if txt[0] != '$': txt = '$' + txt
58          if txt[-1] != '$': txt = txt + '$'
59  
60      fp = open(os.path.join(tmpdir, 'file.tex'), 'w')
61      fp.write(latex_header)
62      fp.write(txt.encode('utf-8') + '\n')
63      fp.write(latex_footer)
64      fp.close()
65      r = subprocess.call(latex_cmd, cwd=tmpdir)
66      if r: raise RuntimeError("Compilation failed")
67      r = subprocess.call(dvipng_cmd, cwd=tmpdir)
68      if r: raise RuntimeError("Compilation failed")
69  
70  def substitute(f):
71      xml = ET.parse(open(f), ET.HTMLParser())
72      images = 0
73      for e in xml.xpath('//span[@class="latexmath"]', namespaces=nsmap):
74          images += build_img(f, e, block=False)
75      for e in xml.xpath('//div[@class="latexmath"]', namespaces=nsmap):
76          images += build_img(f, e, block=True)
77      if not images: return
78      print "Added %d images" % images
79      fp = open(f + ".math", 'w')
80      fp.write(ET.tostring(xml, pretty_print=True, xml_declaration=False, encoding="utf-8"))
81      fp.close()
82      os.unlink(f)
83      #os.rename(f, f + ".pre-math")
84      os.rename(f + ".math", f)
85  
86  tmpdir = tempfile.mkdtemp(dir=cachedir)
87  try:
88      for f in sys.argv[1:]:
89          substitute(f)
90  finally:
91      shutil.rmtree(tmpdir)