diff options
Diffstat (limited to 'docutils/parsers/rst/directives/images.py')
-rw-r--r-- | docutils/parsers/rst/directives/images.py | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/docutils/parsers/rst/directives/images.py b/docutils/parsers/rst/directives/images.py new file mode 100644 index 000000000..5aed4c01b --- /dev/null +++ b/docutils/parsers/rst/directives/images.py @@ -0,0 +1,152 @@ +# Author: David Goodger +# Contact: goodger@users.sourceforge.net +# Revision: $Revision$ +# Date: $Date$ +# Copyright: This module has been placed in the public domain. + +""" +Directives for figures and simple images. +""" + +__docformat__ = 'reStructuredText' + + +import sys +from docutils import nodes, utils +from docutils.parsers.rst import directives, states +from docutils.nodes import fully_normalize_name, whitespace_normalize_name +from docutils.parsers.rst.roles import set_classes + +try: + import Image # PIL +except ImportError: + Image = None + +align_h_values = ('left', 'center', 'right') +align_v_values = ('top', 'middle', 'bottom') +align_values = align_v_values + align_h_values + +def align(argument): + return directives.choice(argument, align_values) + +def image(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + if options.has_key('align'): + # check for align_v values only + if isinstance(state, states.SubstitutionDef): + if options['align'] not in align_v_values: + error = state_machine.reporter.error( + 'Error in "%s" directive: "%s" is not a valid value for ' + 'the "align" option within a substitution definition. ' + 'Valid values for "align" are: "%s".' + % (name, options['align'], '", "'.join(align_v_values)), + nodes.literal_block(block_text, block_text), line=lineno) + return [error] + elif options['align'] not in align_h_values: + error = state_machine.reporter.error( + 'Error in "%s" directive: "%s" is not a valid value for ' + 'the "align" option. Valid values for "align" are: "%s".' + % (name, options['align'], '", "'.join(align_h_values)), + nodes.literal_block(block_text, block_text), line=lineno) + return [error] + messages = [] + reference = directives.uri(arguments[0]) + options['uri'] = reference + reference_node = None + if options.has_key('target'): + block = states.escape2null(options['target']).splitlines() + block = [line for line in block] + target_type, data = state.parse_target(block, block_text, lineno) + if target_type == 'refuri': + reference_node = nodes.reference(refuri=data) + elif target_type == 'refname': + reference_node = nodes.reference( + refname=fully_normalize_name(data), + name=whitespace_normalize_name(data)) + reference_node.indirect_reference_name = data + state.document.note_refname(reference_node) + else: # malformed target + messages.append(data) # data is a system message + del options['target'] + set_classes(options) + image_node = nodes.image(block_text, **options) + if reference_node: + reference_node += image_node + return messages + [reference_node] + else: + return messages + [image_node] + +image.arguments = (1, 0, 1) +image.options = {'alt': directives.unchanged, + 'height': directives.length_or_unitless, + 'width': directives.length_or_percentage_or_unitless, + 'scale': directives.nonnegative_int, + 'align': align, + 'target': directives.unchanged_required, + 'class': directives.class_option} + +def figure_align(argument): + return directives.choice(argument, align_h_values) + +def figure(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + figwidth = options.get('figwidth') + if figwidth: + del options['figwidth'] + figclasses = options.get('figclass') + if figclasses: + del options['figclass'] + align = options.get('align') + if align: + del options['align'] + (image_node,) = image(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine) + if isinstance(image_node, nodes.system_message): + return [image_node] + figure_node = nodes.figure('', image_node) + if figwidth == 'image': + if Image and state.document.settings.file_insertion_enabled: + # PIL doesn't like Unicode paths: + try: + i = Image.open(str(image_node['uri'])) + except (IOError, UnicodeError): + pass + else: + state.document.settings.record_dependencies.add(image_node['uri']) + figure_node['width'] = i.size[0] + elif figwidth is not None: + figure_node['width'] = figwidth + if figclasses: + figure_node['classes'] += figclasses + if align: + figure_node['align'] = align + if content: + node = nodes.Element() # anonymous container for parsing + state.nested_parse(content, content_offset, node) + first_node = node[0] + if isinstance(first_node, nodes.paragraph): + caption = nodes.caption(first_node.rawsource, '', + *first_node.children) + figure_node += caption + elif not (isinstance(first_node, nodes.comment) + and len(first_node) == 0): + error = state_machine.reporter.error( + 'Figure caption must be a paragraph or empty comment.', + nodes.literal_block(block_text, block_text), line=lineno) + return [figure_node, error] + if len(node) > 1: + figure_node += nodes.legend('', *node[1:]) + return [figure_node] + +def figwidth_value(argument): + if argument.lower() == 'image': + return 'image' + else: + return directives.nonnegative_int(argument) + +figure.arguments = (1, 0, 1) +figure.options = {'figwidth': figwidth_value, + 'figclass': directives.class_option} +figure.options.update(image.options) +figure.options['align'] = figure_align +figure.content = 1 |