text: #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  '''
  NAME
      latex2pdf - Converts LaTeX source to PDF file
  
  SYNOPSIS
      latex2pdf [options] INFILE
  
  DESCRIPTION
      This filter reads LaTeX source text from the input file
      INFILE (or stdin if INFILE is -) and renders it to PDF file.
      Typically used to render math equations.
  
      Requires xelatex(1) commands and LaTeX math packages.
  
  OPTIONS
      -o OUTFILE
          The file name of the output file. If not specified the output file is
          named like INFILE but with a .png file name extension.
  
      -m
          Skip if the PDF output file is newer that than the INFILE.
          Compares timestamps on INFILE and OUTFILE. If
          INFILE is - (stdin) then compares MD5 checksum stored in file
          named like OUTFILE but with a .md5 file name extension.
          The .md5 file is created if the -m option is used and the
          INFILE is - (stdin).
  
      -v
          Verbosely print processing information to stderr.
  
      --help, -h
          Print this documentation.
  
      --version
          Print program version number.
  
  SEE ALSO
      xelatex(1)
  
  AUTHOR
      Modified by Thomas Pérennou, <thomas.perennou@aeten.net>
      from PNG version written by Stuart Rackham, <srackham@gmail.com>
      which code was inspired by Kjell Magne Fauske's code:
      http://fauskes.net/nb/htmleqII/
  
      See also:
      http://www.amk.ca/python/code/mt-math
      http://code.google.com/p/latexmath2png/
  
  COPYING
      Copyright (C) 2010 Stuart Rackham. Free use of this software is
      granted under the terms of the MIT License.
      Copyright (C) 2016 Thomas Pérennou (PDF version from PNG).
  '''
  
  # Suppress warning: "the md5 module is deprecated; use hashlib instead"
  import warnings
  warnings.simplefilter('ignore',DeprecationWarning)
  
  import os, sys, tempfile, md5
  
  VERSION = '0.1.0'
  
  # Include LaTeX packages and commands here.
  TEX_HEADER = r'''\documentclass[preview,varwidth]{standalone}
  \usepackage{amsmath}
  \usepackage{amsthm}
  \usepackage{amssymb}
  \usepackage{bm}
  \usepackage{fontspec}
  \usepackage{fancyvrb}
  \setmonofont{Liberation Mono}
  
  \newcommand{\mx}[1]{\mathbf{\bm{#1}}} % Matrix command
  \newcommand{\vc}[1]{\mathbf{\bm{#1}}} % Vector command
  \let\T\relax
  \newcommand{\T}{\textrm{T}}             % Transpose
  
  \begin{document}
  '''
  
  TEX_FOOTER = r'''\end{document}'''
  
  # Globals.
  verbose = False
  
  class EApp(Exception): pass     # Application specific exception.
  
  def print_stderr(line):
      sys.stderr.write(line + os.linesep)
  
  def print_verbose(line):
      if verbose:
          print_stderr(line)
  
  def write_file(filename, data, mode='w'):
      f = open(filename, mode)
      try:
          f.write(data)
      finally:
          f.close()
  
  def read_file(filename, mode='r'):
      f = open(filename, mode)
      try:
          return f.read()
      finally:
          f.close()
  
  def run(cmd):
      global verbose
      if verbose:
          cmd += ' 1>&2'
      else:
          cmd += ' 2>%s 1>&2' % os.devnull
      print_verbose('executing: %s' % cmd)
      if os.system(cmd):
          raise EApp, 'failed command: %s' % cmd
  
  def latex2pdf(infile, outfile, modified):
      '''Convert LaTeX input file infile to PDF file named outfile.'''
      outfile = os.path.abspath(outfile)
      outdir = os.path.dirname(outfile)
      if not os.path.isdir(outdir):
          raise EApp, 'directory does not exist: %s' % outdir
      texfile = tempfile.mktemp(suffix='.tex', dir=os.path.dirname(outfile))
      basefile = os.path.splitext(texfile)[0]
      temps = [basefile + ext for ext in ('.tex', '.aux', '.log')]
      skip = False
      if infile == '-':
          tex = sys.stdin.read()
          if modified:
              checksum = md5.new(tex).digest()
              md5_file = os.path.splitext(outfile)[0] + '.md5'
              if os.path.isfile(md5_file) and os.path.isfile(outfile) and \
                      checksum == read_file(md5_file,'rb'):
                  skip = True
      else:
          if not os.path.isfile(infile):
              raise EApp, 'input file does not exist: %s' % infile
          tex = read_file(infile)
          if modified and os.path.isfile(outfile) and \
                  os.path.getmtime(infile) <= os.path.getmtime(outfile):
              skip = True
      if skip:
          print_verbose('skipped: no change: %s' % outfile)
          return
      tex = '%s\n%s\n%s\n' % (TEX_HEADER, tex.strip(), TEX_FOOTER)
      print_verbose('tex:\n%s' % tex)
      write_file(texfile, tex)
      saved_pwd = os.getcwd()
      os.chdir(outdir)
      try:
          # Compile LaTeX document to PDF file.
          run('xelatex %s' % texfile)
          os.rename(basefile + '.pdf', outfile)
      finally:
          os.chdir(saved_pwd)
          for f in temps:
              if os.path.isfile(f):
                  print_verbose('deleting: %s' % f)
                  os.remove(f)
      if 'md5_file' in locals():
          print_verbose('writing: %s' % md5_file)
          write_file(md5_file, checksum, 'wb')
  
  def usage(msg=''):
      if msg:
          print_stderr(msg)
      print_stderr('\n'
                   'usage:\n'
                   '    latex2pdf [options] INFILE\n'
                   '\n'
                   'options:\n'
                   '    -o OUTFILE\n'
                   '    -m\n'
                   '    -v\n'
                   '    --help\n'
                   '    --version')
  
  def main():
      # Process command line options.
      global verbose
      outfile = None
      modified = False
      import getopt
      opts,args = getopt.getopt(sys.argv[1:], 'D:o:mhv', ['help','version'])
      for o,v in opts:
          if o in ('--help','-h'):
              print __doc__
              sys.exit(0)
          if o =='--version':
              print('latex2pdf version %s' % (VERSION,))
              sys.exit(0)
          if o == '-o': outfile = v
          if o == '-m': modified = True
          if o == '-v': verbose = True
      if len(args) != 1:
          usage()
          sys.exit(1)
      infile = args[0]
      if outfile is None:
          if infile == '-':
              usage('OUTFILE must be specified')
              sys.exit(1)
          outfile = os.path.splitext(infile)[0] + '.png'
      # Do the work.
      latex2pdf(infile, outfile, modified)
      # Print something to suppress asciidoc 'no output from filter' warnings.
      if infile == '-':
          sys.stdout.write(' ')
  
  if __name__ == "__main__":
      try:
          main()
      except SystemExit:
          raise
      except KeyboardInterrupt:
          sys.exit(1)
      except Exception, e:
          print_stderr("%s: %s" % (os.path.basename(sys.argv[0]), str(e)))
          sys.exit(1)
  