diff options
Diffstat (limited to 'doc/asciidoc/filters/latex/latex2png.py')
-rwxr-xr-x | doc/asciidoc/filters/latex/latex2png.py | 232 |
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) |