##// END OF EJS Templates
Merge pull request #11840 from oscargus/enablelatexfontcolor...
Matthias Bussonnier -
r25163:fe0b87c2 merge
parent child Browse files
Show More
@@ -10,6 +10,7 b' import tempfile'
10 import shutil
10 import shutil
11 import subprocess
11 import subprocess
12 from base64 import encodebytes
12 from base64 import encodebytes
13 import textwrap
13
14
14 from IPython.utils.process import find_cmd, FindCmdError
15 from IPython.utils.process import find_cmd, FindCmdError
15 from traitlets.config import get_config
16 from traitlets.config import get_config
@@ -22,7 +23,7 b' class LaTeXTool(SingletonConfigurable):'
22 """An object to store configuration of the LaTeX tool."""
23 """An object to store configuration of the LaTeX tool."""
23 def _config_default(self):
24 def _config_default(self):
24 return get_config()
25 return get_config()
25
26
26 backends = List(
27 backends = List(
27 Unicode(), ["matplotlib", "dvipng"],
28 Unicode(), ["matplotlib", "dvipng"],
28 help="Preferred backend to draw LaTeX math equations. "
29 help="Preferred backend to draw LaTeX math equations. "
@@ -55,7 +56,8 b' class LaTeXTool(SingletonConfigurable):'
55 ).tag(config=True)
56 ).tag(config=True)
56
57
57
58
58 def latex_to_png(s, encode=False, backend=None, wrap=False):
59 def latex_to_png(s, encode=False, backend=None, wrap=False, color='Black',
60 scale=1.0):
59 """Render a LaTeX string to PNG.
61 """Render a LaTeX string to PNG.
60
62
61 Parameters
63 Parameters
@@ -68,6 +70,11 b' def latex_to_png(s, encode=False, backend=None, wrap=False):'
68 Backend for producing PNG data.
70 Backend for producing PNG data.
69 wrap : bool
71 wrap : bool
70 If true, Automatically wrap `s` as a LaTeX equation.
72 If true, Automatically wrap `s` as a LaTeX equation.
73 color : string
74 Foreground color name among dvipsnames, e.g. 'Maroon' or on hex RGB
75 format, e.g. '#AA20FA'.
76 scale : float
77 Scale factor for the resulting PNG.
71
78
72 None is returned when the backend cannot be used.
79 None is returned when the backend cannot be used.
73
80
@@ -82,15 +89,25 b' def latex_to_png(s, encode=False, backend=None, wrap=False):'
82 f = latex_to_png_mpl
89 f = latex_to_png_mpl
83 elif backend == 'dvipng':
90 elif backend == 'dvipng':
84 f = latex_to_png_dvipng
91 f = latex_to_png_dvipng
92 if color.startswith('#'):
93 # Convert hex RGB color to LaTeX RGB color.
94 if len(color) == 7:
95 try:
96 color = "RGB {}".format(" ".join([str(int(x, 16)) for x in
97 textwrap.wrap(color[1:], 2)]))
98 except ValueError:
99 raise ValueError('Invalid color specification {}.'.format(color))
100 else:
101 raise ValueError('Invalid color specification {}.'.format(color))
85 else:
102 else:
86 raise ValueError('No such backend {0}'.format(backend))
103 raise ValueError('No such backend {0}'.format(backend))
87 bin_data = f(s, wrap)
104 bin_data = f(s, wrap, color, scale)
88 if encode and bin_data:
105 if encode and bin_data:
89 bin_data = encodebytes(bin_data)
106 bin_data = encodebytes(bin_data)
90 return bin_data
107 return bin_data
91
108
92
109
93 def latex_to_png_mpl(s, wrap):
110 def latex_to_png_mpl(s, wrap, color='Black', scale=1.0):
94 try:
111 try:
95 from matplotlib import mathtext
112 from matplotlib import mathtext
96 from pyparsing import ParseFatalException
113 from pyparsing import ParseFatalException
@@ -105,13 +122,14 b' def latex_to_png_mpl(s, wrap):'
105 try:
122 try:
106 mt = mathtext.MathTextParser('bitmap')
123 mt = mathtext.MathTextParser('bitmap')
107 f = BytesIO()
124 f = BytesIO()
108 mt.to_png(f, s, fontsize=12)
125 dpi = 120*scale
126 mt.to_png(f, s, fontsize=12, dpi=dpi, color=color)
109 return f.getvalue()
127 return f.getvalue()
110 except (ValueError, RuntimeError, ParseFatalException):
128 except (ValueError, RuntimeError, ParseFatalException):
111 return None
129 return None
112
130
113
131
114 def latex_to_png_dvipng(s, wrap):
132 def latex_to_png_dvipng(s, wrap, color='Black', scale=1.0):
115 try:
133 try:
116 find_cmd('latex')
134 find_cmd('latex')
117 find_cmd('dvipng')
135 find_cmd('dvipng')
@@ -131,10 +149,11 b' def latex_to_png_dvipng(s, wrap):'
131 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
149 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
132 cwd=workdir, stdout=devnull, stderr=devnull)
150 cwd=workdir, stdout=devnull, stderr=devnull)
133
151
152 resolution = round(150*scale)
134 subprocess.check_call(
153 subprocess.check_call(
135 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
154 ["dvipng", "-T", "tight", "-D", str(resolution), "-z", "9",
136 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir,
155 "-bg", "transparent", "-o", outfile, dvifile, "-fg", color],
137 stdout=devnull, stderr=devnull)
156 cwd=workdir, stdout=devnull, stderr=devnull)
138
157
139 with open(outfile, "rb") as f:
158 with open(outfile, "rb") as f:
140 return f.read()
159 return f.read()
@@ -62,7 +62,7 b' def test_latex_to_png_mpl_runs():'
62 @skipif_not_matplotlib
62 @skipif_not_matplotlib
63 def test_latex_to_html():
63 def test_latex_to_html():
64 img = latextools.latex_to_html("$x^2$")
64 img = latextools.latex_to_html("$x^2$")
65 nt.assert_in("data:image/png;base64,iVBOR", img)
65 nt.assert_in("data:image/png;base64,iVBOR", img)
66
66
67
67
68 def test_genelatex_no_wrap():
68 def test_genelatex_no_wrap():
@@ -132,3 +132,50 b' def test_genelatex_wrap_without_breqn():'
132 \begin{document}
132 \begin{document}
133 $$x^2$$
133 $$x^2$$
134 \end{document}''')
134 \end{document}''')
135
136
137 @skipif_not_matplotlib
138 @onlyif_cmds_exist('latex', 'dvipng')
139 def test_latex_to_png_color():
140 """
141 Test color settings for latex_to_png.
142 """
143 latex_string = "$x^2$"
144 default_value = latextools.latex_to_png(latex_string, wrap=False)
145 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
146 color='#000000')
147 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
148 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
149 nt.assert_equal(dvipng_default, dvipng_black)
150 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
151 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
152 nt.assert_equal(mpl_default, mpl_black)
153 nt.assert_in(default_value, [dvipng_black, mpl_black])
154 nt.assert_in(default_hexblack, [dvipng_black, mpl_black])
155
156 # Test that dvips name colors can be used without error
157 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
158 'Maroon')
159 # And that it doesn't return the black one
160 nt.assert_not_equal(dvipng_black, dvipng_maroon)
161
162 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
163 nt.assert_not_equal(mpl_black, mpl_maroon)
164 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
165 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
166 nt.assert_equal(mpl_white, mpl_hexwhite)
167
168 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
169 'White', 1.2)
170 nt.assert_not_equal(mpl_white, mpl_white_scale)
171
172
173 def test_latex_to_png_invalid_hex_colors():
174 """
175 Test that invalid hex colors provided to dvipng gives an exception.
176 """
177 latex_string = "$x^2$"
178 nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string,
179 backend='dvipng', color="#f00bar"))
180 nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string,
181 backend='dvipng', color="#f00"))
General Comments 0
You need to be logged in to leave comments. Login now