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