1"""
2Implement the tikz package for html output.
3The original tikz and latex do most of the work and then pdf2svg (or similar
4software) turns it into a svg image.
5Needs Beautiful Soup, Jinja2, and pdf2svg or similar
6"""
7
8import os
9import string
10import subprocess
11import shutil
12import tempfile
13from plasTeX import Environment, NoCharSubEnvironment, Macro
14from plasTeX.PackageResource import PackageResource
15
16from plasTeX.Logging import getLogger
17log = getLogger()
18
19try:
20    from jinja2 import Template
21except ImportError:
22    log.warning('Cannot find jinja2 lib. Cannot use tikz.')
23
24try:
25    from bs4 import BeautifulSoup
26except ImportError:
27    log.warning('Cannot find BeautifulSoup lib. Cannot use tikz.')
28
29
30class tikzpicture(NoCharSubEnvironment):
31    """
32    A tikz picture whose content will be converted in the processFileContent callback.
33    """
34    class matrix(Environment):
35        """
36        Avoids conflict with amsmath matrix thanks to the context stack
37        mechanism.
38        """
39
40    class draw(Macro):
41        """ Only avoids unrecognized command warning. """
42
43    class fill(Macro):
44        """ Only avoids unrecognized command warning. """
45
46    class filldraw(Macro):
47        """ Only avoids unrecognized command warning. """
48
49    class node(Macro):
50        """ Only avoids unrecognized command warning. """
51
52    class path(Macro):
53        """ Only avoids unrecognized command warning. """
54
55    class clip(Macro):
56        """ Only avoids unrecognized command warning. """
57
58def tikzConvert(document, content, envname, placeholder):
59    tmp_dir = document.userdata[envname]['tmp_dir']
60    working_dir = document.userdata['working-dir']
61    outdir = document.config['files']['directory']
62    outdir = string.Template(outdir).substitute(
63            {'jobname': document.userdata.get('jobname', '')})
64    target_dir = os.path.join(working_dir, outdir, 'images')
65    if not os.path.isdir(target_dir):
66        os.makedirs(target_dir)
67    template = document.userdata[envname]['template']
68    compiler = document.userdata[envname]['compiler']
69    pdf2svg = document.userdata[envname]['pdf2svg']
70
71    cwd = os.getcwd()
72    os.chdir(tmp_dir)
73    soup = BeautifulSoup(content, "html.parser")
74    encoding = soup.original_encoding
75
76    envs = soup.findAll(envname)
77    for env in envs:
78        object_id = env.attrs['id']
79        basepath = os.path.join(tmp_dir, object_id)
80        texpath = basepath + '.tex'
81        pdfpath = basepath + '.pdf'
82        svgpath =  basepath + '.svg'
83
84        context = { 'tikzpicture': env.text.strip() }
85        template.stream(**context).dump(texpath, encoding)
86
87        subprocess.call([compiler, texpath])
88        subprocess.call([pdf2svg, pdfpath, svgpath])
89        destination = os.path.join(target_dir, object_id+'.svg')
90        if os.path.isfile(destination):
91            os.remove(destination)
92        shutil.move(svgpath, target_dir)
93
94        obj = soup.new_tag(
95                'object',
96                type='image/svg+xml',
97                data='images/' + object_id + '.svg')
98        obj.string = document.context.terms.get(
99                placeholder,
100                placeholder) + '\n' + env.text.strip()
101        obj.attrs['class'] = envname
102        div = soup.new_tag('div')
103        div.attrs['class'] = envname
104        div.insert(1, obj)
105
106        env.replace_with(div)
107    os.chdir(cwd)
108    try:
109        # python2
110        result = unicode(soup)
111    except NameError:
112        # python3
113        result = str(soup)
114    return result
115
116def ProcessOptions(options, document):
117    """This is called when the package is loaded."""
118
119    try:
120        with open(document.config['html5']['tikz-template'], "r") as file:
121            template = file.read()
122    except IOError:
123        log.info('Using default TikZ template.')
124        template = u"\\documentclass{standalone}\n\\usepackage{tikz}" + \
125                   u"\\begin{document}{{ tikzpicture }}\\end{document}"
126    document.userdata['tikzpicture'] = {
127            'template': Template(template),
128            'tmp_dir': tempfile.mkdtemp(),
129            'compiler': document.config['html5']['tikz-compiler'],
130            'pdf2svg': document.config['html5']['tikz-converter'],
131            }
132
133    def convert(document, content):
134        return tikzConvert(document, content, 'tikzpicture', 'TikZ picture')
135
136    cb = PackageResource(
137            renderers='html5',
138            key='processFileContents',
139            data=convert)
140    document.addPackageResource(cb)
141