##// END OF EJS Templates
hook up latex tools config to global instance...
Min RK -
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,192 +1,195 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for handling LaTeX."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from io import BytesIO, open
8 8 from base64 import encodestring
9 9 import os
10 10 import tempfile
11 11 import shutil
12 12 import subprocess
13 13
14 14 from IPython.utils.process import find_cmd, FindCmdError
15 from IPython.config.application import Application
15 from IPython.config import get_config
16 16 from IPython.config.configurable import SingletonConfigurable
17 17 from IPython.utils.traitlets import List, Bool, Unicode
18 18 from IPython.utils.py3compat import cast_unicode, cast_unicode_py2 as u
19 19
20 20
21 21 class LaTeXTool(SingletonConfigurable):
22 22 """An object to store configuration of the LaTeX tool."""
23
23 def _config_default(self):
24 return get_config()
25
24 26 backends = List(
25 27 Unicode, ["matplotlib", "dvipng"],
26 28 help="Preferred backend to draw LaTeX math equations. "
27 29 "Backends in the list are checked one by one and the first "
28 30 "usable one is used. Note that `matplotlib` backend "
29 31 "is usable only for inline style equations. To draw "
30 32 "display style equations, `dvipng` backend must be specified. ",
31 33 # It is a List instead of Enum, to make configuration more
32 34 # flexible. For example, to use matplotlib mainly but dvipng
33 35 # for display style, the default ["matplotlib", "dvipng"] can
34 36 # be used. To NOT use dvipng so that other repr such as
35 37 # unicode pretty printing is used, you can use ["matplotlib"].
36 38 config=True)
37 39
38 40 use_breqn = Bool(
39 41 True,
40 42 help="Use breqn.sty to automatically break long equations. "
41 43 "This configuration takes effect only for dvipng backend.",
42 44 config=True)
43 45
44 46 packages = List(
45 47 ['amsmath', 'amsthm', 'amssymb', 'bm'],
46 48 help="A list of packages to use for dvipng backend. "
47 49 "'breqn' will be automatically appended when use_breqn=True.",
48 50 config=True)
49 51
50 52 preamble = Unicode(
51 53 help="Additional preamble to use when generating LaTeX source "
52 54 "for dvipng backend.",
53 55 config=True)
54 56
55 57
56 58 def latex_to_png(s, encode=False, backend=None, wrap=False):
57 59 """Render a LaTeX string to PNG.
58 60
59 61 Parameters
60 62 ----------
61 63 s : text
62 64 The raw string containing valid inline LaTeX.
63 65 encode : bool, optional
64 66 Should the PNG data base64 encoded to make it JSON'able.
65 67 backend : {matplotlib, dvipng}
66 68 Backend for producing PNG data.
67 69 wrap : bool
68 70 If true, Automatically wrap `s` as a LaTeX equation.
69 71
70 72 None is returned when the backend cannot be used.
71 73
72 74 """
73 75 s = cast_unicode(s)
74 76 allowed_backends = LaTeXTool.instance().backends
75 77 if backend is None:
76 78 backend = allowed_backends[0]
77 79 if backend not in allowed_backends:
78 80 return None
79 81 if backend == 'matplotlib':
80 82 f = latex_to_png_mpl
81 83 elif backend == 'dvipng':
82 84 f = latex_to_png_dvipng
83 85 else:
84 86 raise ValueError('No such backend {0}'.format(backend))
85 87 bin_data = f(s, wrap)
86 88 if encode and bin_data:
87 89 bin_data = encodestring(bin_data)
88 90 return bin_data
89 91
90 92
91 93 def latex_to_png_mpl(s, wrap):
92 94 try:
93 95 from matplotlib import mathtext
94 96 except ImportError:
95 97 return None
96
98
97 99 # mpl mathtext doesn't support display math, force inline
98 100 s = s.replace('$$', '$')
99 101 if wrap:
100 102 s = u'${0}$'.format(s)
103
101 104 mt = mathtext.MathTextParser('bitmap')
102 105 f = BytesIO()
103 106 mt.to_png(f, s, fontsize=12)
104 107 return f.getvalue()
105 108
106 109
107 110 def latex_to_png_dvipng(s, wrap):
108 111 try:
109 112 find_cmd('latex')
110 113 find_cmd('dvipng')
111 114 except FindCmdError:
112 115 return None
113 116 try:
114 117 workdir = tempfile.mkdtemp()
115 118 tmpfile = os.path.join(workdir, "tmp.tex")
116 119 dvifile = os.path.join(workdir, "tmp.dvi")
117 120 outfile = os.path.join(workdir, "tmp.png")
118 121
119 122 with open(tmpfile, "w", encoding='utf8') as f:
120 123 f.writelines(genelatex(s, wrap))
121 124
122 125 with open(os.devnull, 'wb') as devnull:
123 126 subprocess.check_call(
124 127 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
125 128 cwd=workdir, stdout=devnull, stderr=devnull)
126 129
127 130 subprocess.check_call(
128 131 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
129 132 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir,
130 133 stdout=devnull, stderr=devnull)
131 134
132 135 with open(outfile, "rb") as f:
133 136 return f.read()
134 137 finally:
135 138 shutil.rmtree(workdir)
136 139
137 140
138 141 def kpsewhich(filename):
139 142 """Invoke kpsewhich command with an argument `filename`."""
140 143 try:
141 144 find_cmd("kpsewhich")
142 145 proc = subprocess.Popen(
143 146 ["kpsewhich", filename],
144 147 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
145 148 (stdout, stderr) = proc.communicate()
146 149 return stdout.strip().decode('utf8', 'replace')
147 150 except FindCmdError:
148 151 pass
149 152
150 153
151 154 def genelatex(body, wrap):
152 155 """Generate LaTeX document for dvipng backend."""
153 156 lt = LaTeXTool.instance()
154 157 breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty")
155 158 yield u(r'\documentclass{article}')
156 159 packages = lt.packages
157 160 if breqn:
158 161 packages = packages + ['breqn']
159 162 for pack in packages:
160 163 yield u(r'\usepackage{{{0}}}'.format(pack))
161 164 yield u(r'\pagestyle{empty}')
162 165 if lt.preamble:
163 166 yield lt.preamble
164 167 yield u(r'\begin{document}')
165 168 if breqn:
166 169 yield u(r'\begin{dmath*}')
167 170 yield body
168 171 yield u(r'\end{dmath*}')
169 172 elif wrap:
170 173 yield u'$${0}$$'.format(body)
171 174 else:
172 175 yield body
173 176 yield u'\end{document}'
174 177
175 178
176 179 _data_uri_template_png = u"""<img src="data:image/png;base64,%s" alt=%s />"""
177 180
178 181 def latex_to_html(s, alt='image'):
179 182 """Render LaTeX to HTML with embedded PNG data using data URIs.
180 183
181 184 Parameters
182 185 ----------
183 186 s : str
184 187 The raw string containing valid inline LateX.
185 188 alt : str
186 189 The alt text to use for the HTML.
187 190 """
188 191 base64_data = latex_to_png(s, encode=True).decode('ascii')
189 192 if base64_data:
190 193 return _data_uri_template_png % (base64_data, alt)
191 194
192 195
General Comments 0
You need to be logged in to leave comments. Login now