##// 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 10 import shutil
11 11 import subprocess
12 12 from base64 import encodebytes
13 import textwrap
13 14
14 15 from IPython.utils.process import find_cmd, FindCmdError
15 16 from traitlets.config import get_config
@@ -22,7 +23,7 b' class LaTeXTool(SingletonConfigurable):'
22 23 """An object to store configuration of the LaTeX tool."""
23 24 def _config_default(self):
24 25 return get_config()
25
26
26 27 backends = List(
27 28 Unicode(), ["matplotlib", "dvipng"],
28 29 help="Preferred backend to draw LaTeX math equations. "
@@ -55,7 +56,8 b' class LaTeXTool(SingletonConfigurable):'
55 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 61 """Render a LaTeX string to PNG.
60 62
61 63 Parameters
@@ -68,6 +70,11 b' def latex_to_png(s, encode=False, backend=None, wrap=False):'
68 70 Backend for producing PNG data.
69 71 wrap : bool
70 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 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 89 f = latex_to_png_mpl
83 90 elif backend == 'dvipng':
84 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 102 else:
86 103 raise ValueError('No such backend {0}'.format(backend))
87 bin_data = f(s, wrap)
104 bin_data = f(s, wrap, color, scale)
88 105 if encode and bin_data:
89 106 bin_data = encodebytes(bin_data)
90 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 111 try:
95 112 from matplotlib import mathtext
96 113 from pyparsing import ParseFatalException
@@ -105,13 +122,14 b' def latex_to_png_mpl(s, wrap):'
105 122 try:
106 123 mt = mathtext.MathTextParser('bitmap')
107 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 127 return f.getvalue()
110 128 except (ValueError, RuntimeError, ParseFatalException):
111 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 133 try:
116 134 find_cmd('latex')
117 135 find_cmd('dvipng')
@@ -131,10 +149,11 b' def latex_to_png_dvipng(s, wrap):'
131 149 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
132 150 cwd=workdir, stdout=devnull, stderr=devnull)
133 151
152 resolution = round(150*scale)
134 153 subprocess.check_call(
135 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
136 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir,
137 stdout=devnull, stderr=devnull)
154 ["dvipng", "-T", "tight", "-D", str(resolution), "-z", "9",
155 "-bg", "transparent", "-o", outfile, dvifile, "-fg", color],
156 cwd=workdir, stdout=devnull, stderr=devnull)
138 157
139 158 with open(outfile, "rb") as f:
140 159 return f.read()
@@ -62,7 +62,7 b' def test_latex_to_png_mpl_runs():'
62 62 @skipif_not_matplotlib
63 63 def test_latex_to_html():
64 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 68 def test_genelatex_no_wrap():
@@ -132,3 +132,50 b' def test_genelatex_wrap_without_breqn():'
132 132 \begin{document}
133 133 $$x^2$$
134 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