Created
November 15, 2017 07:40
-
-
Save jinwei233/3898f30cb532ac055609d49c1efb69f9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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, <[email protected]> | |
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment