diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/ipython/py3/IPython/lib/latextools.py | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/ipython/py3/IPython/lib/latextools.py')
-rw-r--r-- | contrib/python/ipython/py3/IPython/lib/latextools.py | 474 |
1 files changed, 237 insertions, 237 deletions
diff --git a/contrib/python/ipython/py3/IPython/lib/latextools.py b/contrib/python/ipython/py3/IPython/lib/latextools.py index 0e467a57e6..f976f2edb1 100644 --- a/contrib/python/ipython/py3/IPython/lib/latextools.py +++ b/contrib/python/ipython/py3/IPython/lib/latextools.py @@ -1,237 +1,237 @@ -# -*- coding: utf-8 -*- -"""Tools for handling LaTeX.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from io import BytesIO, open -import os -import tempfile -import shutil -import subprocess -from base64 import encodebytes -import textwrap - -from IPython.utils.process import find_cmd, FindCmdError -from traitlets.config import get_config -from traitlets.config.configurable import SingletonConfigurable -from traitlets import List, Bool, Unicode -from IPython.utils.py3compat import cast_unicode - - -class LaTeXTool(SingletonConfigurable): - """An object to store configuration of the LaTeX tool.""" - def _config_default(self): - return get_config() - - backends = List( - Unicode(), ["matplotlib", "dvipng"], - help="Preferred backend to draw LaTeX math equations. " - "Backends in the list are checked one by one and the first " - "usable one is used. Note that `matplotlib` backend " - "is usable only for inline style equations. To draw " - "display style equations, `dvipng` backend must be specified. ", - # It is a List instead of Enum, to make configuration more - # flexible. For example, to use matplotlib mainly but dvipng - # for display style, the default ["matplotlib", "dvipng"] can - # be used. To NOT use dvipng so that other repr such as - # unicode pretty printing is used, you can use ["matplotlib"]. - ).tag(config=True) - - use_breqn = Bool( - True, - help="Use breqn.sty to automatically break long equations. " - "This configuration takes effect only for dvipng backend.", - ).tag(config=True) - - packages = List( - ['amsmath', 'amsthm', 'amssymb', 'bm'], - help="A list of packages to use for dvipng backend. " - "'breqn' will be automatically appended when use_breqn=True.", - ).tag(config=True) - - preamble = Unicode( - help="Additional preamble to use when generating LaTeX source " - "for dvipng backend.", - ).tag(config=True) - - -def latex_to_png(s, encode=False, backend=None, wrap=False, color='Black', - scale=1.0): - """Render a LaTeX string to PNG. - - Parameters - ---------- - s : str - The raw string containing valid inline LaTeX. - encode : bool, optional - Should the PNG data base64 encoded to make it JSON'able. - backend : {matplotlib, dvipng} - Backend for producing PNG data. - wrap : bool - If true, Automatically wrap `s` as a LaTeX equation. - color : string - Foreground color name among dvipsnames, e.g. 'Maroon' or on hex RGB - format, e.g. '#AA20FA'. - scale : float - Scale factor for the resulting PNG. - - None is returned when the backend cannot be used. - - """ - s = cast_unicode(s) - allowed_backends = LaTeXTool.instance().backends - if backend is None: - backend = allowed_backends[0] - if backend not in allowed_backends: - return None - if backend == 'matplotlib': - f = latex_to_png_mpl - elif backend == 'dvipng': - f = latex_to_png_dvipng - if color.startswith('#'): - # Convert hex RGB color to LaTeX RGB color. - if len(color) == 7: - try: - color = "RGB {}".format(" ".join([str(int(x, 16)) for x in - textwrap.wrap(color[1:], 2)])) - except ValueError: - raise ValueError('Invalid color specification {}.'.format(color)) - else: - raise ValueError('Invalid color specification {}.'.format(color)) - else: - raise ValueError('No such backend {0}'.format(backend)) - bin_data = f(s, wrap, color, scale) - if encode and bin_data: - bin_data = encodebytes(bin_data) - return bin_data - - -def latex_to_png_mpl(s, wrap, color='Black', scale=1.0): - try: - from matplotlib import mathtext - from pyparsing import ParseFatalException - except ImportError: - return None - - # mpl mathtext doesn't support display math, force inline - s = s.replace('$$', '$') - if wrap: - s = u'${0}$'.format(s) - - try: - mt = mathtext.MathTextParser('bitmap') - f = BytesIO() - dpi = 120*scale - mt.to_png(f, s, fontsize=12, dpi=dpi, color=color) - return f.getvalue() - except (ValueError, RuntimeError, ParseFatalException): - return None - - -def latex_to_png_dvipng(s, wrap, color='Black', scale=1.0): - try: - find_cmd('latex') - find_cmd('dvipng') - except FindCmdError: - return None - try: - workdir = tempfile.mkdtemp() - tmpfile = os.path.join(workdir, "tmp.tex") - dvifile = os.path.join(workdir, "tmp.dvi") - outfile = os.path.join(workdir, "tmp.png") - - with open(tmpfile, "w", encoding='utf8') as f: - f.writelines(genelatex(s, wrap)) - - with open(os.devnull, 'wb') as devnull: - subprocess.check_call( - ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile], - cwd=workdir, stdout=devnull, stderr=devnull) - - resolution = round(150*scale) - subprocess.check_call( - [ - "dvipng", - "-T", - "tight", - "-D", - str(resolution), - "-z", - "9", - "-bg", - "Transparent", - "-o", - outfile, - dvifile, - "-fg", - color, - ], - cwd=workdir, - stdout=devnull, - stderr=devnull, - ) - - with open(outfile, "rb") as f: - return f.read() - except subprocess.CalledProcessError: - return None - finally: - shutil.rmtree(workdir) - - -def kpsewhich(filename): - """Invoke kpsewhich command with an argument `filename`.""" - try: - find_cmd("kpsewhich") - proc = subprocess.Popen( - ["kpsewhich", filename], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = proc.communicate() - return stdout.strip().decode('utf8', 'replace') - except FindCmdError: - pass - - -def genelatex(body, wrap): - """Generate LaTeX document for dvipng backend.""" - lt = LaTeXTool.instance() - breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty") - yield r'\documentclass{article}' - packages = lt.packages - if breqn: - packages = packages + ['breqn'] - for pack in packages: - yield r'\usepackage{{{0}}}'.format(pack) - yield r'\pagestyle{empty}' - if lt.preamble: - yield lt.preamble - yield r'\begin{document}' - if breqn: - yield r'\begin{dmath*}' - yield body - yield r'\end{dmath*}' - elif wrap: - yield u'$${0}$$'.format(body) - else: - yield body - yield u'\\end{document}' - - -_data_uri_template_png = u"""<img src="data:image/png;base64,%s" alt=%s />""" - -def latex_to_html(s, alt='image'): - """Render LaTeX to HTML with embedded PNG data using data URIs. - - Parameters - ---------- - s : str - The raw string containing valid inline LateX. - alt : str - The alt text to use for the HTML. - """ - base64_data = latex_to_png(s, encode=True).decode('ascii') - if base64_data: - return _data_uri_template_png % (base64_data, alt) - - +# -*- coding: utf-8 -*- +"""Tools for handling LaTeX.""" + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + +from io import BytesIO, open +import os +import tempfile +import shutil +import subprocess +from base64 import encodebytes +import textwrap + +from IPython.utils.process import find_cmd, FindCmdError +from traitlets.config import get_config +from traitlets.config.configurable import SingletonConfigurable +from traitlets import List, Bool, Unicode +from IPython.utils.py3compat import cast_unicode + + +class LaTeXTool(SingletonConfigurable): + """An object to store configuration of the LaTeX tool.""" + def _config_default(self): + return get_config() + + backends = List( + Unicode(), ["matplotlib", "dvipng"], + help="Preferred backend to draw LaTeX math equations. " + "Backends in the list are checked one by one and the first " + "usable one is used. Note that `matplotlib` backend " + "is usable only for inline style equations. To draw " + "display style equations, `dvipng` backend must be specified. ", + # It is a List instead of Enum, to make configuration more + # flexible. For example, to use matplotlib mainly but dvipng + # for display style, the default ["matplotlib", "dvipng"] can + # be used. To NOT use dvipng so that other repr such as + # unicode pretty printing is used, you can use ["matplotlib"]. + ).tag(config=True) + + use_breqn = Bool( + True, + help="Use breqn.sty to automatically break long equations. " + "This configuration takes effect only for dvipng backend.", + ).tag(config=True) + + packages = List( + ['amsmath', 'amsthm', 'amssymb', 'bm'], + help="A list of packages to use for dvipng backend. " + "'breqn' will be automatically appended when use_breqn=True.", + ).tag(config=True) + + preamble = Unicode( + help="Additional preamble to use when generating LaTeX source " + "for dvipng backend.", + ).tag(config=True) + + +def latex_to_png(s, encode=False, backend=None, wrap=False, color='Black', + scale=1.0): + """Render a LaTeX string to PNG. + + Parameters + ---------- + s : str + The raw string containing valid inline LaTeX. + encode : bool, optional + Should the PNG data base64 encoded to make it JSON'able. + backend : {matplotlib, dvipng} + Backend for producing PNG data. + wrap : bool + If true, Automatically wrap `s` as a LaTeX equation. + color : string + Foreground color name among dvipsnames, e.g. 'Maroon' or on hex RGB + format, e.g. '#AA20FA'. + scale : float + Scale factor for the resulting PNG. + + None is returned when the backend cannot be used. + + """ + s = cast_unicode(s) + allowed_backends = LaTeXTool.instance().backends + if backend is None: + backend = allowed_backends[0] + if backend not in allowed_backends: + return None + if backend == 'matplotlib': + f = latex_to_png_mpl + elif backend == 'dvipng': + f = latex_to_png_dvipng + if color.startswith('#'): + # Convert hex RGB color to LaTeX RGB color. + if len(color) == 7: + try: + color = "RGB {}".format(" ".join([str(int(x, 16)) for x in + textwrap.wrap(color[1:], 2)])) + except ValueError: + raise ValueError('Invalid color specification {}.'.format(color)) + else: + raise ValueError('Invalid color specification {}.'.format(color)) + else: + raise ValueError('No such backend {0}'.format(backend)) + bin_data = f(s, wrap, color, scale) + if encode and bin_data: + bin_data = encodebytes(bin_data) + return bin_data + + +def latex_to_png_mpl(s, wrap, color='Black', scale=1.0): + try: + from matplotlib import mathtext + from pyparsing import ParseFatalException + except ImportError: + return None + + # mpl mathtext doesn't support display math, force inline + s = s.replace('$$', '$') + if wrap: + s = u'${0}$'.format(s) + + try: + mt = mathtext.MathTextParser('bitmap') + f = BytesIO() + dpi = 120*scale + mt.to_png(f, s, fontsize=12, dpi=dpi, color=color) + return f.getvalue() + except (ValueError, RuntimeError, ParseFatalException): + return None + + +def latex_to_png_dvipng(s, wrap, color='Black', scale=1.0): + try: + find_cmd('latex') + find_cmd('dvipng') + except FindCmdError: + return None + try: + workdir = tempfile.mkdtemp() + tmpfile = os.path.join(workdir, "tmp.tex") + dvifile = os.path.join(workdir, "tmp.dvi") + outfile = os.path.join(workdir, "tmp.png") + + with open(tmpfile, "w", encoding='utf8') as f: + f.writelines(genelatex(s, wrap)) + + with open(os.devnull, 'wb') as devnull: + subprocess.check_call( + ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile], + cwd=workdir, stdout=devnull, stderr=devnull) + + resolution = round(150*scale) + subprocess.check_call( + [ + "dvipng", + "-T", + "tight", + "-D", + str(resolution), + "-z", + "9", + "-bg", + "Transparent", + "-o", + outfile, + dvifile, + "-fg", + color, + ], + cwd=workdir, + stdout=devnull, + stderr=devnull, + ) + + with open(outfile, "rb") as f: + return f.read() + except subprocess.CalledProcessError: + return None + finally: + shutil.rmtree(workdir) + + +def kpsewhich(filename): + """Invoke kpsewhich command with an argument `filename`.""" + try: + find_cmd("kpsewhich") + proc = subprocess.Popen( + ["kpsewhich", filename], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = proc.communicate() + return stdout.strip().decode('utf8', 'replace') + except FindCmdError: + pass + + +def genelatex(body, wrap): + """Generate LaTeX document for dvipng backend.""" + lt = LaTeXTool.instance() + breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty") + yield r'\documentclass{article}' + packages = lt.packages + if breqn: + packages = packages + ['breqn'] + for pack in packages: + yield r'\usepackage{{{0}}}'.format(pack) + yield r'\pagestyle{empty}' + if lt.preamble: + yield lt.preamble + yield r'\begin{document}' + if breqn: + yield r'\begin{dmath*}' + yield body + yield r'\end{dmath*}' + elif wrap: + yield u'$${0}$$'.format(body) + else: + yield body + yield u'\\end{document}' + + +_data_uri_template_png = u"""<img src="data:image/png;base64,%s" alt=%s />""" + +def latex_to_html(s, alt='image'): + """Render LaTeX to HTML with embedded PNG data using data URIs. + + Parameters + ---------- + s : str + The raw string containing valid inline LateX. + alt : str + The alt text to use for the HTML. + """ + base64_data = latex_to_png(s, encode=True).decode('ascii') + if base64_data: + return _data_uri_template_png % (base64_data, alt) + + |