diff --git a/IPython/extensions/sympyprinting.py b/IPython/extensions/sympyprinting.py index 01eca93..c0bd6c0 100644 --- a/IPython/extensions/sympyprinting.py +++ b/IPython/extensions/sympyprinting.py @@ -11,7 +11,7 @@ pretty-printed. """ #----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team +# Copyright (C) 2008 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. @@ -45,7 +45,9 @@ def print_basic_unicode(o, p, cycle): def print_png(o): - """A function to display sympy expression using LaTex -> PNG.""" + """ + A function to display sympy expression using inline style LaTeX in PNG. + """ s = latex(o, mode='inline') # mathtext does not understand certain latex flags, so we try to replace # them with suitable subs. @@ -54,6 +56,19 @@ def print_png(o): png = latex_to_png(s) return png + +def print_display_png(o): + """ + A function to display sympy expression using display style LaTeX in PNG. + """ + s = latex(o, mode='plain') + s = s.strip('$') + # As matplotlib does not support display style, dvipng backend is + # used here. + png = latex_to_png('$$%s$$' % s, backend='dvipng') + return png + + def can_print_latex(o): """ Return True if type o can be printed with LaTeX. @@ -115,6 +130,9 @@ def load_ipython_extension(ip): png_formatter.for_type_by_name( 'sympy.core.basic', 'Basic', print_png ) + png_formatter.for_type_by_name( + 'sympy.matrices.matrices', 'Matrix', print_display_png + ) for cls in [dict, int, long, float] + printable_containers: png_formatter.for_type(cls, print_png) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index df136e6..1d40746 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -6,7 +6,7 @@ Authors: * Brian Granger """ #----------------------------------------------------------------------------- -# Copyright (C) 2010-2011, IPython Development Team. +# Copyright (C) 2010 IPython Development Team. # # Distributed under the terms of the Modified BSD License. # @@ -19,14 +19,20 @@ Authors: from StringIO import StringIO from base64 import encodestring +import os +import tempfile +import shutil +import subprocess + +from IPython.utils.process import find_cmd, FindCmdError #----------------------------------------------------------------------------- # Tools #----------------------------------------------------------------------------- -def latex_to_png(s, encode=False): - """Render a LaTeX string to PNG using matplotlib.mathtext. +def latex_to_png(s, encode=False, backend='mpl'): + """Render a LaTeX string to PNG. Parameters ---------- @@ -34,18 +40,82 @@ def latex_to_png(s, encode=False): The raw string containing valid inline LaTeX. encode : bool, optional Should the PNG data bebase64 encoded to make it JSON'able. + backend : {mpl, dvipng} + Backend for producing PNG data. + + None is returned when the backend cannot be used. + """ - from matplotlib import mathtext + if backend == 'mpl': + f = latex_to_png_mpl + elif backend == 'dvipng': + f = latex_to_png_dvipng + else: + raise ValueError('No such backend {0}'.format(backend)) + bin_data = f(s) + if encode and bin_data: + bin_data = encodestring(bin_data) + return bin_data + + +def latex_to_png_mpl(s): + try: + from matplotlib import mathtext + except ImportError: + return None mt = mathtext.MathTextParser('bitmap') f = StringIO() mt.to_png(f, s, fontsize=12) - bin_data = f.getvalue() - if encode: - bin_data = encodestring(bin_data) + return f.getvalue() + + +def latex_to_png_dvipng(s): + 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") as f: + f.write(_latex_header) + f.write(s) + f.write(_latex_footer) + + subprocess.check_call( + ["latex", "-halt-on-errror", tmpfile], cwd=workdir, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + subprocess.check_call( + ["dvipng", "-T", "tight", "-x", "1500", "-z", "9", + "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + with open(outfile) as f: + bin_data = f.read() + finally: + shutil.rmtree(workdir) return bin_data +_latex_header = r''' +\documentclass{article} +\usepackage{amsmath} +\usepackage{amsthm} +\usepackage{amssymb} +\usepackage{bm} +\pagestyle{empty} +\begin{document} +''' + +_latex_footer = r'\end{document}' + + _data_uri_template_png = """%s""" def latex_to_html(s, alt='image'): @@ -59,7 +129,8 @@ def latex_to_html(s, alt='image'): The alt text to use for the HTML. """ base64_data = latex_to_png(s, encode=True) - return _data_uri_template_png % (base64_data, alt) + if base64_data: + return _data_uri_template_png % (base64_data, alt) # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we