eqtexsvg.py 5.89 KB
Newer Older
1 2 3
#!/usr/bin/env python
# -*- coding: cp1252 -*-
"""
4 5 6 7
eqtexsvg.py
functions for converting LaTeX equation string into SVG path
This extension need, to work properly:
    - a TeX/LaTeX distribution (MiKTeX ...)
8 9
    - pstoedit software: <http://www.pstoedit.net/pstoedit>

10
Copyright (C) 2006 Julien Vitard <julienvitard@gmail.com>
11

12 13 14
2010-04-04: Added support for custom packages
            Christoph Schmidt-Hieber <christsc@gmx.de>

15 16 17 18 19 20 21 22 23 24 25 26
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
27
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
28 29 30

"""

Thomas Holder's avatar
Thomas Holder committed
31 32
from __future__ import print_function

33
import inkex, os, tempfile, sys, xml.dom.minidom
34

35 36 37 38 39 40 41 42 43
def parse_pkgs(pkgstring):
    pkglist = pkgstring.replace(" ","").split(",")
    header = ""
    for pkg in pkglist:
        header += "\\usepackage{%s}\n" % pkg

    return header

def create_equation_tex(filename, equation, add_header=""):
44
    tex = open(filename, 'w')
45 46 47 48 49
    tex.write("""%% processed with eqtexsvg.py
\\documentclass{article}
\\usepackage{amsmath}
\\usepackage{amssymb}
\\usepackage{amsfonts}
50 51 52
""")
    tex.write(add_header)
    tex.write("""\\thispagestyle{empty}
53 54
\\begin{document}
""")
55
    tex.write(equation)
56
    tex.write("\n\\end{document}\n")
57
    tex.close()
58 59

def svg_open(self,filename):
60 61
    doc_width = self.unittouu(self.document.getroot().get('width'))
    doc_height = self.unittouu(self.document.getroot().get('height'))
62 63 64 65
    doc_sizeH = min(doc_width,doc_height)
    doc_sizeW = max(doc_width,doc_height)

    def clone_and_rewrite(self, node_in):
66 67 68
        in_tag = node_in.tag.rsplit('}',1)[-1]
        if in_tag != 'svg':
            node_out = inkex.etree.Element(inkex.addNS(in_tag,'svg'))
69 70
            for name in node_in.attrib:
                node_out.set(name, node_in.attrib[name])
71
        else:
72 73
            node_out = inkex.etree.Element(inkex.addNS('g','svg'))
        for c in node_in.iterchildren():
74 75
            c_tag = c.tag.rsplit('}',1)[-1]
            if c_tag in ('g', 'path', 'polyline', 'polygon'):
76
                child = clone_and_rewrite(self, c)
77
                if c_tag == 'g':
78 79
                    child.set('transform','matrix('+str(doc_sizeH/700.)+',0,0,'+str(-doc_sizeH/700.)+','+str(-doc_sizeH*0.25)+','+str(doc_sizeW*0.75)+')')
                node_out.append(child)
80 81 82

        return node_out

83 84
    doc = inkex.etree.parse(filename)
    svg = doc.getroot()
85
    group = clone_and_rewrite(self, svg)
86
    self.current_layer.append(group)
87 88

class EQTEXSVG(inkex.Effect):
89 90 91
    def __init__(self):
        inkex.Effect.__init__(self)
        self.OptionParser.add_option("-f", "--formule",
92
                        action="store", type="string",
93
                        dest="formula", default="",
94
                        help="LaTeX formula")
95 96 97 98
        self.OptionParser.add_option("-p", "--packages",
                        action="store", type="string",
                        dest="packages", default="",
                        help="Additional packages")
99 100
    def effect(self):

101 102 103 104 105 106 107 108
        base_dir = tempfile.mkdtemp("", "inkscape-");
        latex_file = os.path.join(base_dir, "eq.tex")
        aux_file = os.path.join(base_dir, "eq.aux")
        log_file = os.path.join(base_dir, "eq.log")
        ps_file = os.path.join(base_dir, "eq.ps")
        dvi_file = os.path.join(base_dir, "eq.dvi")
        svg_file = os.path.join(base_dir, "eq.svg")
        out_file = os.path.join(base_dir, "eq.out")
109
        err_file = os.path.join(base_dir, "eq.err")
110 111 112 113 114 115 116 117 118

        def clean():
            os.remove(latex_file)
            os.remove(aux_file)
            os.remove(log_file)
            os.remove(ps_file)
            os.remove(dvi_file)
            os.remove(svg_file)
            os.remove(out_file)
119 120
            if os.path.exists(err_file):
                os.remove(err_file)
121 122
            os.rmdir(base_dir)

123
        if self.options.formula == "":
Thomas Holder's avatar
Thomas Holder committed
124
            print("empty LaTeX input.  Nothing to be done", file=sys.stderr)
125 126
            return

127 128
        add_header = parse_pkgs(self.options.packages)
        create_equation_tex(latex_file, self.options.formula, add_header)
129 130
        os.system('latex "-output-directory=%s" -halt-on-error "%s" > "%s"' \
                  % (base_dir, latex_file, out_file))
131 132 133
        try:
            os.stat(dvi_file)
        except OSError:
Thomas Holder's avatar
Thomas Holder committed
134 135 136
            print("invalid LaTeX input:", file=sys.stderr)
            print(self.options.formula, file=sys.stderr)
            print("temporary files were left in:", base_dir, file=sys.stderr)
137
            sys.exit(1)
138

139 140 141 142 143 144 145 146
        os.system('dvips -q -f -E -D 600 -y 5000 -o "%s" "%s"' % (ps_file, dvi_file))
        # cd to base_dir is necessary, because pstoedit writes
        # temporary files to cwd and needs write permissions
        separator = ';'
        if os.name == 'nt':
            separator = '&&'
        os.system('cd "%s" %s pstoedit -f plot-svg -dt -ssp "%s" "%s" > "%s" 2> "%s"' \
                  % (base_dir, separator, ps_file, svg_file, out_file, err_file))
147 148 149 150 151 152 153 154 155

        # forward errors to stderr but skip pstoedit header
        if os.path.exists(err_file):
            err_stream = open(err_file, 'r')
            for line in err_stream:
                if not line.startswith('pstoedit: version'):
                    sys.stderr.write(line + '\n')
            err_stream.close()
 
156 157
        svg_open(self, svg_file)

158
        clean()
159

160 161 162
if __name__ == '__main__':
    e = EQTEXSVG()
    e.affect()
163 164


165
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99