##// END OF EJS Templates
make lib.latextools accept unicode...
Min RK -
Show More
@@ -1,23 +1,10 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for handling LaTeX.
2 """Tools for handling LaTeX."""
3
3
4 Authors:
4 # Copyright (c) IPython Development Team.
5
6 * Brian Granger
7 """
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010 IPython Development Team.
10 #
11 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
12 #
13 # The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
6
20 from io import BytesIO
7 from io import BytesIO, open
21 from base64 import encodestring
8 from base64 import encodestring
22 import os
9 import os
23 import tempfile
10 import tempfile
@@ -25,20 +12,17 b' import shutil'
25 import subprocess
12 import subprocess
26
13
27 from IPython.utils.process import find_cmd, FindCmdError
14 from IPython.utils.process import find_cmd, FindCmdError
15 from IPython.config.application import Application
28 from IPython.config.configurable import SingletonConfigurable
16 from IPython.config.configurable import SingletonConfigurable
29 from IPython.utils.traitlets import List, CBool, CUnicode
17 from IPython.utils.traitlets import List, Bool, Unicode
30 from IPython.utils.py3compat import bytes_to_str
18 from IPython.utils.py3compat import cast_unicode, cast_unicode_py2 as u
31
32 #-----------------------------------------------------------------------------
33 # Tools
34 #-----------------------------------------------------------------------------
35
19
36
20
37 class LaTeXTool(SingletonConfigurable):
21 class LaTeXTool(SingletonConfigurable):
38 """An object to store configuration of the LaTeX tool."""
22 """An object to store configuration of the LaTeX tool."""
39
23
40 backends = List(
24 backends = List(
41 CUnicode, ["matplotlib", "dvipng"],
25 Unicode, ["matplotlib", "dvipng"],
42 help="Preferred backend to draw LaTeX math equations. "
26 help="Preferred backend to draw LaTeX math equations. "
43 "Backends in the list are checked one by one and the first "
27 "Backends in the list are checked one by one and the first "
44 "usable one is used. Note that `matplotlib` backend "
28 "usable one is used. Note that `matplotlib` backend "
@@ -51,7 +35,7 b' class LaTeXTool(SingletonConfigurable):'
51 # unicode pretty printing is used, you can use ["matplotlib"].
35 # unicode pretty printing is used, you can use ["matplotlib"].
52 config=True)
36 config=True)
53
37
54 use_breqn = CBool(
38 use_breqn = Bool(
55 True,
39 True,
56 help="Use breqn.sty to automatically break long equations. "
40 help="Use breqn.sty to automatically break long equations. "
57 "This configuration takes effect only for dvipng backend.",
41 "This configuration takes effect only for dvipng backend.",
@@ -63,7 +47,7 b' class LaTeXTool(SingletonConfigurable):'
63 "'breqn' will be automatically appended when use_breqn=True.",
47 "'breqn' will be automatically appended when use_breqn=True.",
64 config=True)
48 config=True)
65
49
66 preamble = CUnicode(
50 preamble = Unicode(
67 help="Additional preamble to use when generating LaTeX source "
51 help="Additional preamble to use when generating LaTeX source "
68 "for dvipng backend.",
52 "for dvipng backend.",
69 config=True)
53 config=True)
@@ -74,10 +58,10 b' def latex_to_png(s, encode=False, backend=None, wrap=False):'
74
58
75 Parameters
59 Parameters
76 ----------
60 ----------
77 s : str
61 s : text
78 The raw string containing valid inline LaTeX.
62 The raw string containing valid inline LaTeX.
79 encode : bool, optional
63 encode : bool, optional
80 Should the PNG data bebase64 encoded to make it JSON'able.
64 Should the PNG data base64 encoded to make it JSON'able.
81 backend : {matplotlib, dvipng}
65 backend : {matplotlib, dvipng}
82 Backend for producing PNG data.
66 Backend for producing PNG data.
83 wrap : bool
67 wrap : bool
@@ -86,6 +70,7 b' def latex_to_png(s, encode=False, backend=None, wrap=False):'
86 None is returned when the backend cannot be used.
70 None is returned when the backend cannot be used.
87
71
88 """
72 """
73 s = cast_unicode(s)
89 allowed_backends = LaTeXTool.instance().backends
74 allowed_backends = LaTeXTool.instance().backends
90 if backend is None:
75 if backend is None:
91 backend = allowed_backends[0]
76 backend = allowed_backends[0]
@@ -110,7 +95,7 b' def latex_to_png_mpl(s, wrap):'
110 return None
95 return None
111
96
112 if wrap:
97 if wrap:
113 s = '${0}$'.format(s)
98 s = u'${0}$'.format(s)
114 mt = mathtext.MathTextParser('bitmap')
99 mt = mathtext.MathTextParser('bitmap')
115 f = BytesIO()
100 f = BytesIO()
116 mt.to_png(f, s, fontsize=12)
101 mt.to_png(f, s, fontsize=12)
@@ -129,10 +114,10 b' def latex_to_png_dvipng(s, wrap):'
129 dvifile = os.path.join(workdir, "tmp.dvi")
114 dvifile = os.path.join(workdir, "tmp.dvi")
130 outfile = os.path.join(workdir, "tmp.png")
115 outfile = os.path.join(workdir, "tmp.png")
131
116
132 with open(tmpfile, "w") as f:
117 with open(tmpfile, "w", encoding='utf8') as f:
133 f.writelines(genelatex(s, wrap))
118 f.writelines(genelatex(s, wrap))
134
119
135 with open(os.devnull, 'w') as devnull:
120 with open(os.devnull, 'wb') as devnull:
136 subprocess.check_call(
121 subprocess.check_call(
137 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
122 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
138 cwd=workdir, stdout=devnull, stderr=devnull)
123 cwd=workdir, stdout=devnull, stderr=devnull)
@@ -156,7 +141,7 b' def kpsewhich(filename):'
156 ["kpsewhich", filename],
141 ["kpsewhich", filename],
157 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
142 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
158 (stdout, stderr) = proc.communicate()
143 (stdout, stderr) = proc.communicate()
159 return stdout.strip()
144 return stdout.strip().decode('utf8', 'replace')
160 except FindCmdError:
145 except FindCmdError:
161 pass
146 pass
162
147
@@ -165,28 +150,28 b' def genelatex(body, wrap):'
165 """Generate LaTeX document for dvipng backend."""
150 """Generate LaTeX document for dvipng backend."""
166 lt = LaTeXTool.instance()
151 lt = LaTeXTool.instance()
167 breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty")
152 breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty")
168 yield r'\documentclass{article}'
153 yield u(r'\documentclass{article}')
169 packages = lt.packages
154 packages = lt.packages
170 if breqn:
155 if breqn:
171 packages = packages + ['breqn']
156 packages = packages + ['breqn']
172 for pack in packages:
157 for pack in packages:
173 yield r'\usepackage{{{0}}}'.format(pack)
158 yield u(r'\usepackage{{{0}}}'.format(pack))
174 yield r'\pagestyle{empty}'
159 yield u(r'\pagestyle{empty}')
175 if lt.preamble:
160 if lt.preamble:
176 yield lt.preamble
161 yield lt.preamble
177 yield r'\begin{document}'
162 yield u(r'\begin{document}')
178 if breqn:
163 if breqn:
179 yield r'\begin{dmath*}'
164 yield u(r'\begin{dmath*}')
180 yield body
165 yield body
181 yield r'\end{dmath*}'
166 yield u(r'\end{dmath*}')
182 elif wrap:
167 elif wrap:
183 yield '$${0}$$'.format(body)
168 yield u'$${0}$$'.format(body)
184 else:
169 else:
185 yield body
170 yield body
186 yield r'\end{document}'
171 yield u'\end{document}'
187
172
188
173
189 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
174 _data_uri_template_png = u"""<img src="data:image/png;base64,%s" alt=%s />"""
190
175
191 def latex_to_html(s, alt='image'):
176 def latex_to_html(s, alt='image'):
192 """Render LaTeX to HTML with embedded PNG data using data URIs.
177 """Render LaTeX to HTML with embedded PNG data using data URIs.
@@ -198,54 +183,8 b" def latex_to_html(s, alt='image'):"
198 alt : str
183 alt : str
199 The alt text to use for the HTML.
184 The alt text to use for the HTML.
200 """
185 """
201 base64_data = bytes_to_str(latex_to_png(s, encode=True), 'ascii')
186 base64_data = latex_to_png(s, encode=True).decode('ascii')
202 if base64_data:
187 if base64_data:
203 return _data_uri_template_png % (base64_data, alt)
188 return _data_uri_template_png % (base64_data, alt)
204
189
205
190
206 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
207 # will remove.
208 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
209 """
210 Given a math expression, renders it in a closely-clipped bounding
211 box to an image file.
212
213 *s*
214 A math expression. The math portion should be enclosed in
215 dollar signs.
216
217 *filename_or_obj*
218 A filepath or writable file-like object to write the image data
219 to.
220
221 *prop*
222 If provided, a FontProperties() object describing the size and
223 style of the text.
224
225 *dpi*
226 Override the output dpi, otherwise use the default associated
227 with the output format.
228
229 *format*
230 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
231 provided, will be deduced from the filename.
232 """
233 from matplotlib import figure
234 # backend_agg supports all of the core output formats
235 from matplotlib.backends import backend_agg
236 from matplotlib.font_manager import FontProperties
237 from matplotlib.mathtext import MathTextParser
238
239 if prop is None:
240 prop = FontProperties()
241
242 parser = MathTextParser('path')
243 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
244
245 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
246 fig.text(0, depth/height, s, fontproperties=prop)
247 backend_agg.FigureCanvasAgg(fig)
248 fig.savefig(filename_or_obj, dpi=dpi, format=format)
249
250 return depth
251
@@ -129,7 +129,6 b' class RichIPythonWidget(IPythonWidget):'
129 self._append_html(self.output_sep2, True)
129 self._append_html(self.output_sep2, True)
130 elif 'text/latex' in data:
130 elif 'text/latex' in data:
131 self._pre_image_append(msg, prompt_number)
131 self._pre_image_append(msg, prompt_number)
132 latex = data['text/latex'].encode('ascii')
133 # latex_to_png takes care of handling $
132 # latex_to_png takes care of handling $
134 latex = latex.strip('$')
133 latex = latex.strip('$')
135 png = latex_to_png(latex, wrap=True)
134 png = latex_to_png(latex, wrap=True)
General Comments 0
You need to be logged in to leave comments. Login now