##// END OF EJS Templates
latex_to_png returns None when the backend cannot be used...
Takafumi Arakaki -
Show More
@@ -1,167 +1,174 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for handling LaTeX.
2 """Tools for handling LaTeX.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010-2011, IPython Development Team.
9 # Copyright (C) 2010-2011, IPython Development Team.
10 #
10 #
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12 #
12 #
13 # The full license is in the file COPYING.txt, distributed with this software.
13 # The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from StringIO import StringIO
20 from StringIO import StringIO
21 from base64 import encodestring
21 from base64 import encodestring
22 import os
22 import os
23 import tempfile
23 import tempfile
24 import shutil
24 import shutil
25 import subprocess
25 import subprocess
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Tools
28 # Tools
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31
31
32 def latex_to_png(s, encode=False, backend='mpl'):
32 def latex_to_png(s, encode=False, backend='mpl'):
33 """Render a LaTeX string to PNG.
33 """Render a LaTeX string to PNG.
34
34
35 Parameters
35 Parameters
36 ----------
36 ----------
37 s : str
37 s : str
38 The raw string containing valid inline LaTeX.
38 The raw string containing valid inline LaTeX.
39 encode : bool, optional
39 encode : bool, optional
40 Should the PNG data bebase64 encoded to make it JSON'able.
40 Should the PNG data bebase64 encoded to make it JSON'able.
41 backend : {mpl, dvipng}
41 backend : {mpl, dvipng}
42 Backend for producing PNG data.
42 Backend for producing PNG data.
43
43
44 None is returned when the backend cannot be used.
45
44 """
46 """
45 if backend == 'mpl':
47 if backend == 'mpl':
46 f = latex_to_png_mpl
48 f = latex_to_png_mpl
47 elif backend == 'dvipng':
49 elif backend == 'dvipng':
48 f = latex_to_png_dvipng
50 f = latex_to_png_dvipng
49 else:
51 else:
50 raise ValueError('No such backend {0}'.format(backend))
52 raise ValueError('No such backend {0}'.format(backend))
51 bin_data = f(s)
53 bin_data = f(s)
52 if encode:
54 if encode and bin_data:
53 bin_data = encodestring(bin_data)
55 bin_data = encodestring(bin_data)
54 return bin_data
56 return bin_data
55
57
56
58
57 def latex_to_png_mpl(s):
59 def latex_to_png_mpl(s):
58 from matplotlib import mathtext
60 try:
61 from matplotlib import mathtext
62 except ImportError:
63 return None
59
64
60 mt = mathtext.MathTextParser('bitmap')
65 mt = mathtext.MathTextParser('bitmap')
61 f = StringIO()
66 f = StringIO()
62 mt.to_png(f, s, fontsize=12)
67 mt.to_png(f, s, fontsize=12)
63 return f.getvalue()
68 return f.getvalue()
64
69
65
70
66 def latex_to_png_dvipng(s):
71 def latex_to_png_dvipng(s):
67 try:
72 try:
68 workdir = tempfile.mkdtemp()
73 workdir = tempfile.mkdtemp()
69 tmpfile = os.path.join(workdir, "tmp.tex")
74 tmpfile = os.path.join(workdir, "tmp.tex")
70 dvifile = os.path.join(workdir, "tmp.dvi")
75 dvifile = os.path.join(workdir, "tmp.dvi")
71 outfile = os.path.join(workdir, "tmp.png")
76 outfile = os.path.join(workdir, "tmp.png")
72
77
73 with open(tmpfile, "w") as f:
78 with open(tmpfile, "w") as f:
74 f.write(_latex_header)
79 f.write(_latex_header)
75 f.write(s)
80 f.write(s)
76 f.write(_latex_footer)
81 f.write(_latex_footer)
77
82
78 subprocess.check_call(
83 subprocess.check_call(
79 ["latex", "-halt-on-errror", tmpfile], cwd=workdir)
84 ["latex", "-halt-on-errror", tmpfile], cwd=workdir)
80
85
81 subprocess.check_call(
86 subprocess.check_call(
82 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
87 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
83 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir)
88 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir)
84
89
85 with open(outfile) as f:
90 with open(outfile) as f:
86 bin_data = f.read()
91 bin_data = f.read()
92 except subprocess.CalledProcessError:
93 bin_data = None
87 finally:
94 finally:
88 shutil.rmtree(workdir)
95 shutil.rmtree(workdir)
89 return bin_data
96 return bin_data
90
97
91
98
92
93 _latex_header = r'''
99 _latex_header = r'''
94 \documentclass{article}
100 \documentclass{article}
95 \usepackage{amsmath}
101 \usepackage{amsmath}
96 \usepackage{amsthm}
102 \usepackage{amsthm}
97 \usepackage{amssymb}
103 \usepackage{amssymb}
98 \usepackage{bm}
104 \usepackage{bm}
99 \pagestyle{empty}
105 \pagestyle{empty}
100 \begin{document}
106 \begin{document}
101 '''
107 '''
102
108
103 _latex_footer = r'\end{document}'
109 _latex_footer = r'\end{document}'
104
110
105
111
106 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
112 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
107
113
108 def latex_to_html(s, alt='image'):
114 def latex_to_html(s, alt='image'):
109 """Render LaTeX to HTML with embedded PNG data using data URIs.
115 """Render LaTeX to HTML with embedded PNG data using data URIs.
110
116
111 Parameters
117 Parameters
112 ----------
118 ----------
113 s : str
119 s : str
114 The raw string containing valid inline LateX.
120 The raw string containing valid inline LateX.
115 alt : str
121 alt : str
116 The alt text to use for the HTML.
122 The alt text to use for the HTML.
117 """
123 """
118 base64_data = latex_to_png(s, encode=True)
124 base64_data = latex_to_png(s, encode=True)
119 return _data_uri_template_png % (base64_data, alt)
125 if base64_data:
126 return _data_uri_template_png % (base64_data, alt)
120
127
121
128
122 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
129 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
123 # will remove.
130 # will remove.
124 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
131 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
125 """
132 """
126 Given a math expression, renders it in a closely-clipped bounding
133 Given a math expression, renders it in a closely-clipped bounding
127 box to an image file.
134 box to an image file.
128
135
129 *s*
136 *s*
130 A math expression. The math portion should be enclosed in
137 A math expression. The math portion should be enclosed in
131 dollar signs.
138 dollar signs.
132
139
133 *filename_or_obj*
140 *filename_or_obj*
134 A filepath or writable file-like object to write the image data
141 A filepath or writable file-like object to write the image data
135 to.
142 to.
136
143
137 *prop*
144 *prop*
138 If provided, a FontProperties() object describing the size and
145 If provided, a FontProperties() object describing the size and
139 style of the text.
146 style of the text.
140
147
141 *dpi*
148 *dpi*
142 Override the output dpi, otherwise use the default associated
149 Override the output dpi, otherwise use the default associated
143 with the output format.
150 with the output format.
144
151
145 *format*
152 *format*
146 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
153 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
147 provided, will be deduced from the filename.
154 provided, will be deduced from the filename.
148 """
155 """
149 from matplotlib import figure
156 from matplotlib import figure
150 # backend_agg supports all of the core output formats
157 # backend_agg supports all of the core output formats
151 from matplotlib.backends import backend_agg
158 from matplotlib.backends import backend_agg
152 from matplotlib.font_manager import FontProperties
159 from matplotlib.font_manager import FontProperties
153 from matplotlib.mathtext import MathTextParser
160 from matplotlib.mathtext import MathTextParser
154
161
155 if prop is None:
162 if prop is None:
156 prop = FontProperties()
163 prop = FontProperties()
157
164
158 parser = MathTextParser('path')
165 parser = MathTextParser('path')
159 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
166 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
160
167
161 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
168 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
162 fig.text(0, depth/height, s, fontproperties=prop)
169 fig.text(0, depth/height, s, fontproperties=prop)
163 backend_agg.FigureCanvasAgg(fig)
170 backend_agg.FigureCanvasAgg(fig)
164 fig.savefig(filename_or_obj, dpi=dpi, format=format)
171 fig.savefig(filename_or_obj, dpi=dpi, format=format)
165
172
166 return depth
173 return depth
167
174
General Comments 0
You need to be logged in to leave comments. Login now