Source code for docutils.utils.math.tex2mathml_extern

# :Id: $Id: tex2mathml_extern.py 9250 2022-11-16 14:01:31Z milde $
# :Copyright: © 2015 Günter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
#    Copying and distribution of this file, with or without modification,
#    are permitted in any medium without royalty provided the copyright
#    notice and this notice are preserved.
#    This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: https://opensource.org/licenses/BSD-2-Clause

"""Wrappers for TeX->MathML conversion by external tools

This module is provisional:
the API is not settled and may change with any minor Docutils version.
"""

import subprocess

document_template = r"""\documentclass{article}
\usepackage{amsmath}
\begin{document}
%s
\end{document}
"""


[docs] def latexml(math_code, reporter=None): """Convert LaTeX math code to MathML with LaTeXML_ .. _LaTeXML: http://dlmf.nist.gov/LaTeXML/ """ p = subprocess.Popen(['latexml', '-', # read from stdin '--preload=amsfonts', '--preload=amsmath', '--inputencoding=utf8', ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) p.stdin.write((document_template % math_code).encode('utf-8')) p.stdin.close() latexml_code = p.stdout.read() latexml_err = p.stderr.read().decode('utf-8') if reporter and (latexml_err.find('Error') >= 0 or not latexml_code): reporter.error(latexml_err) post_p = subprocess.Popen(['latexmlpost', '-', '--nonumbersections', '--format=xhtml', # '--linelength=78', # experimental '--' ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) post_p.stdin.write(latexml_code) post_p.stdin.close() result = post_p.stdout.read().decode('utf-8') post_p_err = post_p.stderr.read().decode('utf-8') if reporter and (post_p_err.find('Error') >= 0 or not result): reporter.error(post_p_err) # extract MathML code: start, end = result.find('<math'), result.find('</math>')+7 result = result[start:end] if 'class="ltx_ERROR' in result: raise SyntaxError(result) return result
[docs] def ttm(math_code, reporter=None): """Convert LaTeX math code to MathML with TtM_ .. _TtM: http://hutchinson.belmont.ma.us/tth/mml/ """ p = subprocess.Popen(['ttm', # '-i', # italic font for equations. Default roman. '-u', # unicode encoding. (Default iso-8859-1). '-r', # output raw MathML (no wrapper) ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) p.stdin.write((document_template % math_code).encode('utf-8')) p.stdin.close() result = p.stdout.read() err = p.stderr.read().decode('utf-8') if err.find('**** Unknown') >= 0: msg = '\n'.join(line for line in err.splitlines() if line.startswith('****')) raise SyntaxError('\nMessage from external converter TtM:\n'+msg) if reporter and err.find('**** Error') >= 0 or not result: reporter.error(err) start, end = result.find('<math'), result.find('</math>')+7 return result[start:end]
[docs] def blahtexml(math_code, inline=True, reporter=None): """Convert LaTeX math code to MathML with blahtexml_ .. _blahtexml: http://gva.noekeon.org/blahtexml/ """ options = ['--mathml', '--indented', '--spacing', 'moderate', '--mathml-encoding', 'raw', '--other-encoding', 'raw', '--doctype-xhtml+mathml', '--annotate-TeX', ] if inline: mathmode_arg = '' else: mathmode_arg = ' display="block"' options.append('--displaymath') p = subprocess.Popen(['blahtexml']+options, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) p.stdin.write(math_code.encode('utf-8')) p.stdin.close() result = p.stdout.read().decode('utf-8') err = p.stderr.read().decode('utf-8') if result.find('<error>') >= 0: msg = result[result.find('<message>')+9:result.find('</message>')] raise SyntaxError('\nMessage from external converter blahtexml:\n%s' % msg) if reporter and (err.find('**** Error') >= 0 or not result): reporter.error(err) start, end = result.find('<markup>')+9, result.find('</markup>') result = ('<math xmlns="http://www.w3.org/1998/Math/MathML"%s>\n' '%s</math>\n') % (mathmode_arg, result[start:end]) return result
[docs] def pandoc(math_code, reporter=None): """Convert LaTeX math code to MathML with pandoc_ .. _pandoc: https://pandoc.org/ """ p = subprocess.Popen(['pandoc', '--mathml', '--from=latex', ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) p.stdin.write(math_code.encode('utf-8')) p.stdin.close() result = p.stdout.read().decode('utf-8') err = p.stderr.read().decode('utf-8').strip() x = p.wait() if err: if reporter: reporter.error(err) raise SyntaxError('\nError message from external converter pandoc:\n%s' % err) if x != 0: raise SyntaxError('\nError code from external converter pandoc:\n%s' % x) start, end = result.find('<math'), result.find('</math>')+7 return result[start:end]
# self-test if __name__ == "__main__": example = ('\\frac{\\partial \\sin^2(\\alpha)}{\\partial \\vec r}' '\\varpi \\mathbb{R} \\, \\text{Grüße}') # print(latexml('$'+example+'$')) # print(ttm('$'+example.replace('\\mathbb{R}', '')+'$')) print(blahtexml(example)) # print(pandoc('$'+example+'$'))