ENH: Update FreeFOAM contributions to GPL v3
[freefoam.git] / data / utilities / foamPNGMathFilter.py.in
blobd1500f5af81d3f1e2a2631761a29e3141ffb4f97
1 #!@PYTHON_EXECUTABLE@
2 #-------------------------------------------------------------------------------
3 # ______ _ ____ __ __
4 # | ____| _| |_ / __ \ /\ | \/ |
5 # | |__ _ __ ___ ___ / \| | | | / \ | \ / |
6 # | __| '__/ _ \/ _ ( (| |) ) | | |/ /\ \ | |\/| |
7 # | | | | | __/ __/\_ _/| |__| / ____ \| | | |
8 # |_| |_| \___|\___| |_| \____/_/ \_\_| |_|
10 # FreeFOAM: The Cross-Platform CFD Toolkit
12 # Copyright (C) 2008-2012 Michael Wild <themiwi@users.sf.net>
13 # Gerber van der Graaf <gerber_graaf@users.sf.net>
14 #-------------------------------------------------------------------------------
15 # License
16 # This file is part of FreeFOAM.
18 # FreeFOAM is free software: you can redistribute it and/or modify it
19 # under the terms of the GNU General Public License as published by the
20 # Free Software Foundation, either version 3 of the License, or (at your
21 # option) any later version.
23 # FreeFOAM is distributed in the hope that it will be useful, but WITHOUT
24 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 # for more details.
28 # You should have received a copy of the GNU General Public License
29 # along with FreeFOAM. If not, see <http://www.gnu.org/licenses/>.
30 #-------------------------------------------------------------------------------
32 # Script
33 # foamPNGMathFilter.py
35 #------------------------------------------------------------------------------
37 """Usage:
38 foamPNGMathFilter.py [-D dpi] [-m <mathdir>] [-o <outfile>] [<infile>]
40 Filters the AsciiDoc source file read from standard input (or `<infile>` if
41 specified) and replaces all inline and block maths by PNG images generated
42 using `latex` and `dvipng`. The filtered source is written to standard output
43 or (`<outfile>` if specified). The created images are either written to the
44 `math` directory in the current working directory, or if an output file has
45 been specified, in the directory containing the output file. The `-m` option
46 overrides this choice. The file is named `math_<md5sum>.png`.
48 Options
49 -------
50 -D Specify the resolution of the output images. Refer to dvipng(1)
51 -m Overrides the default output directory for the generated graphics
52 -o <outfile> Specifies that the output should be written to `<outfile>`
53 instead of the standard output
55 """
57 # Suppress warning: "the md5 module is deprecated; use hashlib instead"
58 import warnings
59 warnings.simplefilter('ignore',DeprecationWarning)
61 import md5
62 import os
63 import os.path
64 import re
65 import shutil
66 import subprocess
67 import sys
68 import tempfile
69 sys.path.insert(0, '@FOAM_PYTHON_DIR@')
70 from FreeFOAM.compat import *
72 # argument parsing
73 args = sys.argv[1:]
74 dpiopt = '-D 120'
75 mathdir = None
76 outname = None
77 while len(args):
78 # process options
79 if args[0] == '-D':
80 if len(args) < 2:
81 echo('ERROR: -D option requires argument', file=sys.stderr)
82 sys.exit(1)
83 dpiopt = ' '.join(args[0:2])
84 del args[0:2]
85 continue
86 if args[0] == '-m':
87 if len(args) < 2:
88 echo('ERROR: -m option requires argument', file=sys.stderr)
89 sys.exit(1)
90 mathdir = args[1]
91 del args[0:2]
92 continue
93 if args[0] == '-o':
94 if len(args) < 2:
95 echo('ERROR: -o option requires argument', file=sys.stderr)
96 sys.exit(1)
97 outname = args[1]
98 del args[0:2]
99 continue
100 if args[0] != '-':
101 break
102 else:
103 echo('ERROR: Unknown option "%s"'%args[0], file=sys.stderr)
104 sys.exit(1)
106 if len(args) == 1:
107 infile = open(args[0], 'rt')
108 elif not len(args):
109 infile = sys.stdin
110 else:
111 echo('ERROR: Only one non-option argument allowed', file=sys.stderr)
112 sys.exit(1)
114 if outname:
115 outdir = os.path.dirname(outname)
116 if not os.path.isdir(outdir):
117 os.makedirs(outdir)
118 outfile = open(outname, 'wt')
119 else:
120 outfile = sys.stdout
121 outdir = os.getcwd()
123 if not mathdir:
124 mathdir = os.path.join(outdir, 'math')
126 absmathdir = os.path.isabs(mathdir) and mathdir or os.path.join(pwd, mathdir)
127 #relmathdir = os.path.relpath(mathdir, outdir)
129 LATEXHEAD = r'''
130 \documentclass[12pt]{article}
131 \usepackage[utf8x]{inputenc}
132 \usepackage{amsmath}
133 \usepackage{amsthm}
134 \usepackage{amssymb}
135 \usepackage{amsfonts}
136 \usepackage{bm}
137 \input{@FOAM_DATA_DIR@/asciidoc/dblatex/foam-macros.sty}
138 \pagestyle{empty}
139 \begin{document}
142 LATEXSEP = r'''
143 \clearpage
146 LATEXFOOT = r'''
147 \end{document}
150 regexes = {
151 'inlinemacro': re.compile(
152 r'(?su)[\\]?(?P<name>math):(?P<subslist>\S*?)\[(?P<mathtext>.*?)'
153 + r'(?<!\\)\]'),
154 'blockmacro': re.compile(
155 r'(?su)[\\]?(?P<name>math)::(?P<subslist>\S*?)\[(?P<mathtext>.*?)'
156 + r'(?<!\\)\]'),
157 'block': re.compile(
158 r'(?sum)^\[(?P<name>math)\]\n(?:\+{4,})\n(?P<mathtext>.*?)\n'
159 + r'(?:\+{4,})$'),
162 lines = ''.join(infile.readlines())
164 matches = []
165 for name, regex in regexes.iteritems():
166 for m in regex.finditer(lines):
167 mathtext = m.group('mathtext')
168 h = md5.new(name+dpiopt+mathtext).hexdigest()
169 matches.append({
170 'match' : m,
171 'name' : name,
172 'mathtext' : mathtext,
173 'begin' : m.start(),
174 'end' : m.end(),
175 'hash' : h,
176 'outname' : 'math_%s.png'%h
179 matches.sort(key=lambda x: x['begin'], reverse=True)
181 latextext = ''
182 hashes = {}
183 idx = 1
184 for m in matches:
185 #imname = os.path.join(relmathdir, m['outname'])
186 imname = os.path.join(absmathdir, m['outname'])
187 mathtext = m['mathtext']
188 if m['name'] in 'inlinemacro blockmacro'.split():
189 sep = ':'
190 cleanmathtext = mathtext.replace(r'\]', ']')
191 if m['name'] == 'inlinemacro':
192 cleanmathtext = '$%s$'%cleanmathtext
193 else:
194 sep += ':'
195 replacement = 'math%s%s[%s]'%(sep,imname,mathtext)
196 elif m['name'] == 'block':
197 cleanmathtext = mathtext
198 replacement = '[math,%s]\n++++++\n%s\n++++++'%(imname,mathtext)
200 lines = lines[:m['begin']]+replacement+lines[m['end']:]
201 if not m['hash'] in hashes and not os.path.isfile(
202 os.path.join(absmathdir,m['outname'])):
203 hashes[m['hash']] = {
204 'idx' : idx,
205 'tmpname' : 'math%d.png'%idx,
206 'outname' : m['outname'],
207 'mathtext' : cleanmathtext,
209 idx += 1
210 latextext += cleanmathtext + LATEXSEP
212 if len(latextext):
213 pwd = os.getcwd()
214 tmpdir = None
215 latextext = LATEXHEAD + latextext + LATEXFOOT
216 try:
217 if not os.path.isdir(absmathdir):
218 os.makedirs(absmathdir)
219 tmpdir = tempfile.mkdtemp()
220 os.chdir(tmpdir)
221 open('math.tex', 'wt').write(latextext)
222 subprocess.check_call([
223 '@LATEX_EXECUTABLE@',
224 '--interaction=nonstopmode', 'math.tex'],
225 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
226 subprocess.check_call([
227 '@DVIPNG_EXECUTABLE@',
228 '-T', 'tight', '-z9', dpiopt, 'math.dvi'],
229 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
230 for d in hashes.itervalues():
231 shutil.move(d['tmpname'], os.path.join(absmathdir, d['outname']))
232 finally:
233 os.chdir(pwd)
234 if tmpdir is not None:
235 shutil.rmtree(tmpdir)
237 outfile.write(lines)
239 # ------------------------- vim: set sw=3 sts=3 et: --------------- end-of-file