summaryrefslogtreecommitdiff
path: root/doc/asciidoc/filters/latex/latex2png.py
diff options
context:
space:
mode:
Diffstat (limited to 'doc/asciidoc/filters/latex/latex2png.py')
-rwxr-xr-xdoc/asciidoc/filters/latex/latex2png.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/doc/asciidoc/filters/latex/latex2png.py b/doc/asciidoc/filters/latex/latex2png.py
new file mode 100755
index 0000000..3cae7c9
--- /dev/null
+++ b/doc/asciidoc/filters/latex/latex2png.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python
+'''
+NAME
+ latex2png - Converts LaTeX source to PNG file
+
+SYNOPSIS
+ latex2png [options] INFILE
+
+DESCRIPTION
+ This filter reads LaTeX source text from the input file
+ INFILE (or stdin if INFILE is -) and renders it to PNG image file.
+ Typically used to render math equations.
+
+ Requires latex(1), dvipng(1) commands and LaTeX math packages.
+
+OPTIONS
+ -D DPI
+ Set the output resolution to DPI dots per inch. Use this option to
+ scale the output image size.
+
+ -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 PNG 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
+ latex(1), dvipng(1)
+
+AUTHOR
+ Written by Stuart Rackham, <srackham@gmail.com>
+ The 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.
+'''
+
+# 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{article}
+\usepackage{amsmath}
+\usepackage{amsthm}
+\usepackage{amssymb}
+\usepackage{bm}
+\newcommand{\mx}[1]{\mathbf{\bm{#1}}} % Matrix command
+\newcommand{\vc}[1]{\mathbf{\bm{#1}}} % Vector command
+\newcommand{\T}{\text{T}} % Transpose
+\pagestyle{empty}
+\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 latex2png(infile, outfile, dpi, modified):
+ '''Convert LaTeX input file infile to PNG 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]
+ dvifile = basefile + '.dvi'
+ temps = [basefile + ext for ext in ('.tex','.dvi', '.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 DVI file.
+ run('latex %s' % texfile)
+ # Convert DVI file to PNG.
+ cmd = 'dvipng'
+ if dpi:
+ cmd += ' -D %s' % dpi
+ cmd += ' -T tight -x 1000 -z 9 -bg Transparent --truecolor -o "%s" "%s" ' \
+ % (outfile,dvifile)
+ run(cmd)
+ 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'
+ ' latex2png [options] INFILE\n'
+ '\n'
+ 'options:\n'
+ ' -D DPI\n'
+ ' -o OUTFILE\n'
+ ' -m\n'
+ ' -v\n'
+ ' --help\n'
+ ' --version')
+
+def main():
+ # Process command line options.
+ global verbose
+ dpi = None
+ 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('latex2png version %s' % (VERSION,))
+ sys.exit(0)
+ if o == '-D': dpi = v
+ 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 dpi and not dpi.isdigit():
+ usage('invalid DPI')
+ sys.exit(1)
+ if outfile is None:
+ if infile == '-':
+ usage('OUTFILE must be specified')
+ sys.exit(1)
+ outfile = os.path.splitext(infile)[0] + '.png'
+ # Do the work.
+ latex2png(infile, outfile, dpi, 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)