]> git.llucax.com Git - z.facultad/75.00/informe.git/blob - ext/aafig.py
Ordenar alfabéticamente las referencias
[z.facultad/75.00/informe.git] / ext / aafig.py
1 # -*- coding: utf-8 -*-
2 """
3     sphinxcontrib.aafig
4     ~~~~~~~~~~~~~~~~~~~
5
6     Allow embeded ASCII art to be rendered as nice looking images
7     using the aafigure reStructuredText extension.
8
9     See the README file for details.
10
11     :author: Leandro Lucarella <llucax@gmail.com>
12     :license: BOLA, see LICENSE for details
13 """
14
15 import posixpath
16 from os import path
17 try:
18     from hashlib import sha1 as sha
19 except ImportError:
20     from sha import sha
21
22 from docutils import nodes
23 from docutils.parsers.rst import directives
24
25 from sphinx.errors import SphinxError
26 from sphinx.util import ensuredir
27 from sphinx.util.compat import Directive
28
29 try:
30     import aafigure
31 except ImportError:
32     aafigure = None
33
34
35 DEFAULT_FORMATS = dict(html='svg', latex='pdf', text=None)
36
37
38 def merge_dict(dst, src):
39     for (k, v) in src.items():
40         if k not in dst:
41             dst[k] = v
42     return dst
43
44
45 def get_basename(text, options, prefix='aafig'):
46     options = options.copy()
47     if 'format' in options:
48         del options['format']
49     hashkey = text.encode('utf-8') + str(options)
50     id = sha(hashkey).hexdigest()
51     return '%s-%s' % (prefix, id)
52
53
54 class AafigError(SphinxError):
55     category = 'aafig error'
56
57
58 class AafigDirective(directives.images.Image):
59     """
60     Directive to insert an ASCII art figure to be rendered by aafigure.
61     """
62     has_content = True
63     required_arguments = 0
64     own_option_spec = dict(
65         line_width   = float,
66         background   = str,
67         foreground   = str,
68         fill         = str,
69         aspect       = directives.nonnegative_int,
70         textual      = directives.flag,
71         proportional = directives.flag,
72     )
73     option_spec = directives.images.Image.option_spec.copy()
74     option_spec.update(own_option_spec)
75
76     def run(self):
77         aafig_options = dict()
78         image_attrs = dict()
79         own_options_keys = self.own_option_spec.keys() + ['scale']
80         for (k, v) in self.options.items():
81             if k in own_options_keys:
82                 # convert flags to booleans
83                 if v is None:
84                     v = True
85                 # convert percentage to float
86                 if k == 'scale' or k == 'aspect':
87                     v = float(v) / 100.0
88                 aafig_options[k] = v
89                 del self.options[k]
90         self.arguments = ['']
91         (image_node,) = directives.images.Image.run(self)
92         if isinstance(image_node, nodes.system_message):
93             return [image_node]
94         text = '\n'.join(self.content)
95         image_node.aafig = dict(options = aafig_options, text = text)
96         return [image_node]
97
98
99 def render_aafig_images(app, doctree):
100     format_map = app.builder.config.aafig_format
101     merge_dict(format_map, DEFAULT_FORMATS)
102     for img in doctree.traverse(nodes.image):
103         if not hasattr(img, 'aafig'):
104             continue
105
106         options = img.aafig['options']
107         text = img.aafig['text']
108         format = app.builder.format
109         merge_dict(options, app.builder.config.aafig_default_options)
110         if format in format_map:
111             options['format'] = format_map[format]
112         else:
113             app.builder.warn('unsupported builder format "%s", please '
114                     'add a custom entry in aafig_format config option '
115                     'for this builder' % format)
116             img.replace_self(nodes.literal_block(text, text))
117             continue
118         if options['format'] is None:
119             img.replace_self(nodes.literal_block(text, text))
120             continue
121         try:
122             fname, outfn, id, extra = render_aafigure(app, text, options)
123         except AafigError, exc:
124             app.builder.warn('aafigure error: ' + str(exc))
125             img.replace_self(nodes.literal_block(text, text))
126             continue
127         img['uri'] = fname
128         # FIXME: find some way to avoid this hack in aafigure
129         if extra:
130             (width, height) = [x.split('"')[1] for x in extra.split()]
131             if not img.has_key('width'):
132                 img['width'] = width
133             if not img.has_key('height'):
134                 img['height'] = height
135
136
137 def render_aafigure(app, text, options):
138     """
139     Render an ASCII art figure into the requested format output file.
140     """
141
142     if aafigure is None:
143         raise AafigError('aafigure module not installed')
144
145     fname = get_basename(text, options)
146     fname = '%s.%s' % (get_basename(text, options), options['format'])
147     if hasattr(app.builder, 'imgpath'):
148         # HTML
149         relfn = posixpath.join(app.builder.imgpath, fname)
150         outfn = path.join(app.builder.outdir, '_images', fname)
151     else:
152         # LaTeX
153         relfn = fname
154         outfn = path.join(app.builder.outdir, fname)
155     metadata_fname = '%s.aafig' % outfn
156
157     try:
158         if path.isfile(outfn):
159             extra = None
160             if options['format'].lower() == 'svg':
161                 f = None
162                 try:
163                     try:
164                         f = file(metadata_fname, 'r')
165                         extra = f.read()
166                     except:
167                         raise AafigError()
168                 finally:
169                     if f is not None:
170                         f.close()
171             return relfn, outfn, id, extra
172     except AafigError:
173         pass
174
175     ensuredir(path.dirname(outfn))
176
177     try:
178         (visitor, output) = aafigure.render(text, outfn, options)
179         output.close()
180     except aafigure.UnsupportedFormatError, e:
181         raise AafigError(str(e))
182
183     extra = None
184     if options['format'].lower() == 'svg':
185         extra = visitor.get_size_attrs()
186         f = file(metadata_fname, 'w')
187         f.write(extra)
188         f.close()
189
190     return relfn, outfn, id, extra
191
192
193 def setup(app):
194     app.add_directive('aafig', AafigDirective)
195     app.connect('doctree-read', render_aafig_images)
196     app.add_config_value('aafig_format', DEFAULT_FORMATS, 'html')
197     app.add_config_value('aafig_default_options', dict(), 'html')
198