def run(self): figclasses = self.options.pop('figclass', None) (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figclasses: figure_node['classes'] += figclasses figure_node['classes'] += ['m-figure'] if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): set_classes(self.options) text = '\n'.join(self.content) figure_node = nodes.figure(text, **self.options) figure_node['classes'] += self.style_classes self.state.nested_parse(self.content, self.content_offset, figure_node) # Insert the title node, if any, right after the code / math / graph. # There could be things like the class directive before, so be sure to # find the right node. if len(self.arguments) == 1: title_text = self.arguments[0] title_nodes, _ = self.state.inline_text(title_text, self.lineno) title_node = nodes.caption('', '', *title_nodes) for i, child in enumerate(figure_node): if isinstance(child, nodes.raw) or isinstance(child, nodes.literal_block): figure_node.insert(i + 1, title_node) break else: assert False # pragma: no cover return [figure_node]
def run(self): try: data = retrieve_glue_data(self.document, self.arguments[0]) except RetrievalError as exc: return [glue_warning(str(exc), self.document, self.line)] render: Dict[str, Any] = {} for key in ("alt", "height", "width", "scale", "class"): if key in self.options: render.setdefault("image", {})[key.replace("classes", "class")] = self.options[key] paste_nodes = render_variable_output(data, self.document, self.line, self.source, render=render) # note: most of this is copied directly from sphinx.Figure # create figure node figure_node = nodes.figure("", *paste_nodes) self.set_source_info(figure_node) # add attributes figwidth = self.options.pop("figwidth", None) figclasses = self.options.pop("figclass", None) align = self.options.pop("align", None) if figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align # add target self.add_name(figure_node) # create the caption and legend if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = glue_warning( "Figure caption must be a paragraph or empty comment.", self.document, self.lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def run(self): results = super(BlockdiagDirective, self).run() node = results[0] if not isinstance(node, self.node_class): return results try: diagram = self.node2diagram(node) except Exception as e: raise self.warning(e.message) if 'desctable' in node['options']: del node['options']['desctable'] results += self.description_tables(diagram) results[0] = self.node2image(node, diagram) if 'caption' in node: fig = nodes.figure() fig += results[0] fig += nodes.caption(text=node['caption']) results[0] = fig return results
def run(self): node = dag() node['dag'] = '\n'.join(self.content) node['caption'] = '\n'.join(self.arguments) if not self.content: node['caption'] = '' node['dag'] = '\n'.join(self.arguments) node['bugfixed'] = False try: if sphinx.version_info[0] >= 1 and sphinx.version_info[1] >= 4: node['bugfixed'] = True except AttributeError: pass if node['bugfixed'] and node['caption']: figure_node = nodes.figure('', node) parsed = nodes.Element() self.state.nested_parse(ViewList([node['caption']], source=''), self.content_offset, parsed) caption_node = nodes.caption(parsed[0].rawsource, '', *parsed[0].children) caption_node.source = parsed[0].source caption_node.line = parsed[0].line figure_node += caption_node node = figure_node return [node]
def run(self): figclasses = self.options.pop('figclass', None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figclasses: figure_node['classes'] += figclasses figure_node['classes'] += ['m-figure'] if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): env = self.state.document.settings.env node = nodes.Element() node.document = self.state.document self.state.nested_parse(self.content, self.content_offset, node) images = [] caption_and_legend = [] for child in node: if isinstance(child, (nodes.target, nodes.image, nodes.figure)): images.append(child) else: caption_and_legend.append(child) items = [] row_item_count = min( len(images), self.options.get('rowitems', DEFAULT_ROW_ITEM_COUNT)) labels = self.options.get('labels', []) for img, label in itertools.zip_longest(images, labels): item_node = multifigure_item('', img) item_node['item-width'] = 100 // row_item_count if label is not None: item_node['label'] = label items.append(item_node) caption, legend = caption_and_legend[0], caption_and_legend[1:] resultnode = nodes.figure('', multifigure_content('', *items)) resultnode['labels'] = labels resultnode.append(nodes.caption(caption.rawsource, '', *caption)) if legend: resultnode.append(nodes.legend('', *legend)) return [resultnode]
def apply (self): if self.document.settings.no_images: return for image in self.document.traverse (nodes.image): # skip inline images # (See also: class `TextElement` in `docutils.nodes`.) if isinstance (image.parent, nodes.TextElement): continue # block images default align = center image['classes'].append ('block') image['align'] = image.attributes.get ('align', 'center') # wrap all images into figures if not isinstance (image.parent, nodes.figure): figure = nodes.figure () figure['float'] = ['none'] # do not float bare images figure['width'] = image.attributes.get ('width', 'image') image['width'] = '100%' figure['align'] = image['align'] image.replace_self (figure) figure.append (image) # set a default width for block images image['width'] = image.attributes.get ('width', '100%') figure = image.parent if figure['width'] == 'image': figure['width'] = self.get_width (image['uri']) figure['classes'].append ('auto-scaled')
def run(self): set_classes(self.options) text = '\n'.join(self.content) figure_node = nodes.figure(text, **self.options) figure_node['classes'] += self.style_classes self.state.nested_parse(self.content, self.content_offset, figure_node) # Insert the title node, if any, right after the code / math / graph. # There could be things like the class directive before, so be sure to # find the right node. if len(self.arguments) == 1: title_text = self.arguments[0] title_nodes, _ = self.state.inline_text(title_text, self.lineno) title_node = nodes.caption('', '', *title_nodes) for i, child in enumerate(figure_node): if isinstance(child, nodes.raw) or isinstance( child, nodes.literal_block): figure_node.insert(i + 1, title_node) break else: assert False # pragma: no cover return [figure_node]
def run(self): from sphinx.util.nodes import set_source_info from sphinx.util.i18n import search_image_for_language warning = self.state.document.reporter.warning env = self.state.document.settings.env if self.arguments and self.content: return [ warning( 'uml directive cannot have both content and ' 'a filename argument', line=self.lineno) ] if self.arguments: fn = search_image_for_language(self.arguments[0], env) relfn, absfn = env.relfn2path(fn) env.note_dependency(relfn) try: umlcode = sphinxcontrib.plantuml._read_utf8(absfn) except (IOError, UnicodeDecodeError) as err: return [ warning('PlantUML file "%s" cannot be read: %s' % (fn, err), line=self.lineno) ] source = absfn line = 1 else: relfn = env.doc2path(env.docname, base=None) umlcode = '\n'.join(self.content) source, line = self.state_machine.get_source_and_line( self.content_offset) node = sphinxcontrib.plantuml.plantuml(self.block_text, **self.options) node['uml'] = umlcode node['incdir'] = os.path.dirname(relfn) node['filename'] = os.path.split(relfn)[1] node.source, node.line = source, line # XXX maybe this should be moved to _visit_plantuml functions. it # seems wrong to insert "figure" node by "plantuml" directive. if 'caption' in self.options or 'align' in self.options: node = nodes.figure('', node) if 'align' in self.options: node['align'] = self.options['align'] if 'caption' in self.options: inodes, messages = self.state.inline_text(self.options['caption'], self.lineno) caption_node = nodes.caption(self.options['caption'], '', *inodes) caption_node.extend(messages) set_source_info(self, caption_node) node += caption_node self.add_name(node) if 'html_format' in self.options: node['html_format'] = self.options['html_format'] if 'latex_format' in self.options: node['latex_format'] = self.options['latex_format'] return [node]
def run(self): set_classes(self.options) text = '\n'.join(self.content) figure_node = nodes.figure(text, **self.options) figure_node['classes'] += [self.style_class] self.state.nested_parse(self.content, self.content_offset, figure_node) return [figure_node]
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (media_node,) = Media.run(self) if isinstance(media_node, nodes.system_message): return [media_node] figure_node = nodes.figure('', media_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(media_node['uri'])) except (IOError, UnicodeError): pass else: self.state.document.settings.record_dependencies.add( media_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 self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.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 = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) node = figure_node node['label'] = self.options.get('label', None) if not node['label']: node['label'] = self.options.get('uri') node['number'] = None ret = [node] if node['label']: key = node['label'] tnode = nodes.target('', '', ids=['figure-' + node['label']]) self.state.document.note_explicit_target(tnode) ret.insert(0, tnode) return ret
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', ["right"]) align = self.options.pop('align', None) (media_node, ) = Media.run(self) if isinstance(media_node, nodes.system_message): return [media_node] figure_node = nodes.figure('', media_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(media_node['uri'])) except (IOError, UnicodeError): pass else: self.state.document.settings.record_dependencies.add( media_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 self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.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 = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) node = figure_node node['label'] = self.options.get('label', None) if not node['label']: node['label'] = self.options.get('uri') node['number'] = None ret = [node] if node['label']: key = node['label'] tnode = nodes.target('', '', ids=['figure-' + node['label']]) self.state.document.note_explicit_target(tnode) ret.insert(0, tnode) return ret
def run(self): figure = nodes.figure() # Figure out what the show for this demo py_path = Path(self.arguments[0]) zip_path = py_path.parent / (py_path.stem + '_assets.zip') png_path = py_path.parent / (py_path.stem + '.png') # Error out if the given python script doesn't exist. if py_path.suffix != '.py': raise self.error(f"'{py_path}' must be a python script.") if not py_path.exists(): raise self.error(f"'{py_path}' doesn't exist.") if self.content: # Make sure the content is present in the given file. Complain if # there are differences. from textwrap import dedent with open(py_path) as py_file: py_code = [l.strip() for l in py_file.readlines()] for py_line in self.content: if py_line.strip() not in py_code: raise self.error(f"""\ Error in \"demo\" directive: The following line isn't present in '{py_path}': {py_line}""") # Add a node for the code snippet from sphinx.directives.code import CodeBlock figure += self.make_snippet(self.content, png_path.exists()) # Add a node for the screenshot if png_path.exists(): figure += self.make_screenshot(png_path) # Add a node for the download links. caption = nodes.caption() caption += self.make_download_link(py_path) if zip_path.exists(): caption += linebreak() caption += self.make_download_link(zip_path) figure += caption return [figure]
def run(self): figwidth = self.options.pop('figwidth', None) position = self.options.pop('position', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: self.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 position: figure_node['position'] = position if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] cap = first_node.astext().strip() if re.match('[Tt]he.*',cap): print >>sys.stderr, "WARNING: Style: Caption '%s' begins with 'The'" % cap 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 = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) else: self.state.document.reporter.error('Figure without caption\n', line = self.lineno) return [figure_node]
def figure_wrapper(directive, node, caption): figure_node = nodes.figure('', node) parsed = nodes.Element() directive.state.nested_parse(ViewList([caption], source=''), directive.content_offset, parsed) caption_node = nodes.caption(parsed[0].rawsource, '', *parsed[0].children) caption_node.source = parsed[0].source caption_node.line = parsed[0].line figure_node += caption_node return figure_node
def figure_wrapper(directive: Directive, node: graphviz, caption: str) -> nodes.figure: figure_node = nodes.figure('', node) if 'align' in node: figure_node['align'] = node.attributes.pop('align') inodes, messages = directive.state.inline_text(caption, directive.lineno) caption_node = nodes.caption(caption, '', *inodes) caption_node.extend(messages) set_source_info(directive, caption_node) figure_node += caption_node return figure_node
def figure_wrapper(directive, node, caption): # type: (Directive, graphviz, str) -> nodes.figure figure_node = nodes.figure('', node) if 'align' in node: figure_node['align'] = node.attributes.pop('align') inodes, messages = directive.state.inline_text(caption, directive.lineno) caption_node = nodes.caption(caption, '', *inodes) caption_node.extend(messages) set_source_info(directive, caption_node) figure_node += caption_node return figure_node
def run(self): grid_node = nodes.container() grid_node['classes'] += ['m-imagegrid', 'm-container-inflate'] rows = [[]] total_widths = [0] for uri in self.content: # New line, calculating width from 0 again if not uri: rows.append([]) total_widths.append(0) continue # Open the files and calculate the overall width absuri = uri.format( filename=os.path.join(os.getcwd(), settings['PATH'])) im = PIL.Image.open(absuri) exif = { PIL.ExifTags.TAGS[k]: v for k, v in im._getexif().items() if k in PIL.ExifTags.TAGS and len(str(v)) < 256 } # Can't use just *exif['ExposureTime'] on Py3.4 caption = "F{}, {}/{} s, ISO {}".format( float(exif['FNumber'][0]) / float(exif['FNumber'][1]), exif['ExposureTime'][0], exif['ExposureTime'][1], exif['ISOSpeedRatings']) rel_width = float(im.width) / im.height total_widths[-1] += rel_width rows[-1].append((uri, rel_width, len(total_widths) - 1, caption)) for row in rows: row_node = nodes.container() for image in row: image_reference = rst.directives.uri(image[0]) image_node = nodes.image('', uri=image_reference) text_nodes, _ = self.state.inline_text(image[3], self.lineno) text_node = nodes.paragraph('', '', *text_nodes) overlay_node = nodes.caption() overlay_node.append(text_node) link_node = nodes.reference('', refuri=image_reference) link_node.append(image_node) link_node.append(overlay_node) wrapper_node = nodes.figure( width="{:.3f}%".format(image[1] * 100.0 / total_widths[image[2]])) wrapper_node.append(link_node) row_node.append(wrapper_node) grid_node.append(row_node) return [grid_node]
def figure_wrapper(directive, node, caption): figure_node = nodes.figure("", node) if "align" in node: figure_node["align"] = node.attributes.pop("align") parsed = nodes.Element() directive.state.nested_parse(ViewList([caption], source=""), directive.content_offset, parsed) caption_node = nodes.caption(parsed[0].rawsource, "", *parsed[0].children) caption_node.source = parsed[0].source caption_node.line = parsed[0].line figure_node += caption_node return figure_node
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: imagepath = urllib.url2pathname(image_node['uri']) try: if isinstance(imagepath, str): imagepath_str = imagepath else: imagepath_str = imagepath.encode( sys.getfilesystemencoding()) img = PIL.Image.open(imagepath_str) except (IOError, UnicodeEncodeError): pass # TODO: warn? else: self.state.document.settings.record_dependencies.add( imagepath.replace('\\', '/')) figure_node['width'] = '%dpx' % img.size[0] del img elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) if self.options.get('caption'): align = self.options.pop('align', None) else: align = None results = super(BlockdiagDirective, self).run() node = results[0] if not isinstance(node, self.node_class): return results try: diagram = self.node2diagram(node) except Exception as e: raise self.warning(str(e)) if 'desctable' in node['options']: results += self.description_tables(diagram) results[0] = self.node2image(node, diagram) self.add_name(results[0]) if node.get('caption'): elem = nodes.Element() self.state.nested_parse(ViewList([node['caption']], source=''), self.content_offset, elem) caption_node = nodes.caption(elem[0].rawsource, '', *elem[0].children) caption_node.source = elem[0].source caption_node.line = elem[0].line fig = nodes.figure() fig += results[0] fig += caption_node if figwidth == 'image': width = self.get_actual_width(node, diagram) fig['width'] = str(width) + 'px' elif figwidth is not None: fig['width'] = figwidth if figclasses: fig['classes'] += figclasses if align: fig['align'] = align results[0] = fig return results
def run(self): warning = self.state.document.reporter.warning env = self.state.document.settings.env if self.arguments and self.content: return [ warning( 'uml directive cannot have both content and ' 'a filename argument', line=self.lineno) ] if self.arguments: fn = search_image_for_language(self.arguments[0], env) relfn, absfn = env.relfn2path(fn) env.note_dependency(relfn) try: umlcode = _read_utf8(absfn) except (IOError, UnicodeDecodeError) as err: return [ warning('PlantUML file "%s" cannot be read: %s' % (fn, err), line=self.lineno) ] else: relfn = env.doc2path(env.docname, base=None) umlcode = '\n'.join(self.content) node = plantuml(self.block_text, **self.options) node['uml'] = umlcode node['incdir'] = os.path.dirname(relfn) node['filename'] = os.path.split(relfn)[1] # XXX maybe this should be moved to _visit_plantuml functions. it # seems wrong to insert "figure" node by "plantuml" directive. if 'caption' in self.options or 'align' in self.options: node = nodes.figure('', node) if 'align' in self.options: node['align'] = self.options['align'] if 'caption' in self.options: import docutils.statemachine cnode = nodes.Element() # anonymous container for parsing sl = docutils.statemachine.StringList([self.options['caption']], source='') self.state.nested_parse(sl, self.content_offset, cnode) caption = nodes.caption(self.options['caption'], '', *cnode) node += caption if 'html_format' in self.options: node['html_format'] = self.options['html_format'] if 'latex_format' in self.options: node['latex_format'] = self.options['latex_format'] return [node]
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 run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: imagepath = urllib.url2pathname(image_node['uri']) try: if isinstance(imagepath, str): imagepath_str = imagepath else: imagepath_str = imagepath.encode(sys.getfilesystemencoding()) img = PIL.Image.open(imagepath_str) except (IOError, UnicodeEncodeError): pass # TODO: warn? else: self.state.document.settings.record_dependencies.add( imagepath.replace('\\', '/')) figure_node['width'] = '%dpx' % img.size[0] del img elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def figure_wrapper(directive, node, caption): # type: (Directive, nodes.Node, unicode) -> nodes.figure figure_node = nodes.figure('', node) if 'align' in node: figure_node['align'] = node.attributes.pop('align') parsed = nodes.Element() directive.state.nested_parse(ViewList([caption], source=''), directive.content_offset, parsed) caption_node = nodes.caption(parsed[0].rawsource, '', *parsed[0].children) caption_node.source = parsed[0].source caption_node.line = parsed[0].line figure_node += caption_node return figure_node
def run(self): figwidth = self.options.get('figwidth') if figwidth: del self.options['figwidth'] figclasses = self.options.get('figclass') if figclasses: del self.options['figclass'] align = self.options.get('align') if align: del self.options['align'] (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: self.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 self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.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 = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): node = plantuml(self.block_text, **self.options) node['uml'] = '\n'.join(self.content) # if a caption is defined, insert a 'figure' with this node and the caption if 'caption' in self.options: import docutils.statemachine cnode = nodes.Element() # anonymous container for parsing sl = docutils.statemachine.StringList([self.options['caption']],source='') self.state.nested_parse(sl,self.content_offset, cnode) caption = nodes.caption(self.options['caption'], '', *cnode) fig = nodes.figure('',node) fig += caption node = fig return [node]
def run(self): figwidth = self.options.pop("figwidth", None) figclasses = self.options.pop("figclass", None) align = self.options.pop("align", None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure("", image_node) if figwidth == "image": if PIL and self.state.document.settings.file_insertion_enabled: imagepath = url2pathname(image_node["uri"]) try: img = PIL.Image.open( imagepath.encode(sys.getfilesystemencoding())) except (IOError, UnicodeEncodeError): pass # TODO: warn? else: self.state.document.settings.record_dependencies.add( imagepath.replace("\\", "/")) figure_node["width"] = "%dpx" % img.size[0] del img elif figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( "Figure caption must be a paragraph or empty comment.", nodes.literal_block(self.block_text, self.block_text), line=self.lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def run(self): node = plantuml(self.block_text, **self.options) node['uml'] = '\n'.join(self.content) # if a caption is defined, insert a 'figure' with this node and the caption if 'caption' in self.options: import docutils.statemachine cnode = nodes.Element() # anonymous container for parsing sl = docutils.statemachine.StringList([self.options['caption']], source='') self.state.nested_parse(sl, self.content_offset, cnode) caption = nodes.caption(self.options['caption'], '', *cnode) fig = nodes.figure('', node) fig += caption node = fig return [node]
def run(self): self.options['width'] = '95%' label = self.options.get('label', None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node, ids=[label] if label is not None else []) figure_node['align'] = 'center' if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption_node = nodes.caption(first_node.rawsource, '', *first_node.children) caption_node.source = first_node.source caption_node.line = first_node.line figure_node += caption_node elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Subfigure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) else: rst = ViewList() rst.append(self.options['caption'], "", 0) parsed_node = nodes.section() parsed_node.document = self.state.document nested_parse_with_titles(self.state, rst, parsed_node) node = parsed_node[0] caption_node = nodes.caption(node.rawsource, '', *node.children) caption_node.source = node.source caption_node.line = node.line figure_node += caption_node return [figure_node]
def sourcecode( name, arguments, options, content, lineno, content_offset, block_text, state, state_machine, ): filename = options.get('filename', None) if filename is None: code = u'\n'.join(content) else: source = state_machine.input_lines.source( lineno - state_machine.input_offset - 1) source_dir = os.path.dirname(os.path.abspath(source)) filename = os.path.normpath(os.path.join(source_dir, filename)) filename = utils.relative_path(None, filename) state.document.settings.record_dependencies.add(filename) op = state.document.settings.roast_operation inp = op.open_input(filename) code = inp.read().decode('utf-8') inp.close() if arguments: (syntax,) = arguments else: syntax = 'text' lexer = lexers.get_lexer_by_name(syntax) formatter = formatters.HtmlFormatter() html = highlight( code=code, lexer=lexer, formatter=formatter, ) title_text = options.get('title') if title_text: text_nodes, messages = state.inline_text(title_text, lineno) title = nodes.caption('', '# ', *text_nodes) else: messages = [] title = None fig = nodes.figure('') fig['classes'].append('py-listing') if title is not None: fig += title fig += nodes.raw('', html, format='html') return [fig] + messages
def run(self): name, = self.content source_name, scenario = name.rsplit("-", 1) source = source_name + ".sam" image_reference = directives.uri("_images/" + name + ".png") self.options["uri"] = image_reference source_link = nodes.reference(self.content, source, refuri="examples/" + source) # text = nodes.text('', 'Output from ' + source) image_node = nodes.image("_images/" + name + ".png", **self.options) figure_node = nodes.figure("", image_node) msg = "Output from " if scenario != "baseline": msg += "'" + scenario + "' in " caption = nodes.caption("hi", msg, source_link) figure_node += caption return [figure_node]
def build_node(self): srclang = self.arguments[0].strip() if srclang not in RENDER_MARKUP_EXT.keys(): return [ self.state_machine.reporter.warning( 'Unknown source language "%s", use one of: %s.' % (srclang, ",".join(RENDER_MARKUP_EXT.keys())), line=self.lineno) ] code = '\n'.join(self.content) if not code.strip(): return [ self.state_machine.reporter.warning( 'Ignoring "%s" directive without content.' % (self.name), line=self.lineno) ] node = kernel_render() node['alt'] = self.options.get('alt', '') node['srclang'] = srclang literal_node = nodes.literal_block(code, code) node += literal_node caption = self.options.get('caption') if caption: # parse caption's content parsed = nodes.Element() self.state.nested_parse(ViewList([caption], source=''), self.content_offset, parsed) caption_node = nodes.caption(parsed[0].rawsource, '', *parsed[0].children) caption_node.source = parsed[0].source caption_node.line = parsed[0].line figure_node = nodes.figure('', node) for k, v in self.options.items(): figure_node[k] = v figure_node += caption_node node = figure_node return node
def figure(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): figwidth = options.setdefault("figwidth") figclasses = options.setdefault("figclass") align = options.setdefault("align") del options["figwidth"] del options["figclass"] 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 test_process_doc_handle_figure_caption(): env = mock.Mock(domaindata={}) figure_node = nodes.figure( '', nodes.caption('caption text', 'caption text'), ) document = mock.Mock( nametypes={'testname': True}, nameids={'testname': 'testid'}, ids={'testid': figure_node}, ) domain = StandardDomain(env) if 'testname' in domain.data['labels']: del domain.data['labels']['testname'] domain.process_doc(env, 'testdoc', document) assert 'testname' in domain.data['labels'] assert domain.data['labels']['testname'] == ('testdoc', 'testid', 'caption text')
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) if self.options.get('caption'): align = self.options.pop('align', None) else: align = None results = super(BlockdiagDirective, self).run() node = results[0] if not isinstance(node, self.node_class): return results try: diagram = self.node2diagram(node) except Exception as e: raise self.warning(str(e)) if 'desctable' in node['options']: results += self.description_tables(diagram) results[0] = self.node2image(node, diagram) self.add_name(results[0]) if node.get('caption'): fig = nodes.figure() fig += results[0] fig += nodes.caption(text=node['caption']) if figwidth == 'image': width = self.get_actual_width(node, diagram) fig['width'] = str(width) + 'px' elif figwidth is not None: fig['width'] = figwidth if figclasses: fig['classes'] += figclasses if align: fig['align'] = align results[0] = fig return results
def test_process_doc_handle_figure_caption(): env = mock.Mock(domaindata={}) figure_node = nodes.figure( '', nodes.caption('caption text', 'caption text'), ) document = mock.Mock( nametypes={'testname': True}, nameids={'testname': 'testid'}, ids={'testid': figure_node}, ) domain = StandardDomain(env) if 'testname' in domain.data['labels']: del domain.data['labels']['testname'] domain.process_doc(env, 'testdoc', document) assert 'testname' in domain.data['labels'] assert domain.data['labels']['testname'] == ( 'testdoc', 'testid', 'caption text')
def run(self): figwidth = self.options.pop("figwidth", None) figclasses = self.options.pop("figclass", None) align = self.options.pop("align", None) # On the Paste node we should add an attribute to specify that only image # type mimedata is allowed, then this would be used by # PasteNodesToDocutils -> CellOutputsToNodes to alter the render priority # and/or log warnings if that type of mimedata is not available (paste_node, ) = Paste.run(self) if isinstance(paste_node, nodes.system_message): return [paste_node] figure_node = nodes.figure("", paste_node) figure_node.line = paste_node.line figure_node.source = paste_node.source if figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align self.add_name(figure_node) # note: this is copied directly from sphinx.Figure if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( "Figure caption must be a paragraph or empty comment.", nodes.literal_block(self.block_text, self.block_text), line=self.lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def run(self): id = self.arguments[0] [only_html, only_pdf] = youtube_embed(id) # TODO: should we skip figure if no caption? figure_node = nodes.figure("") figure_node += only_html figure_node += only_pdf has_caption = len(self.content) > 0 if has_caption: caption = self.content[0] inodes, messages = self.state.inline_text(caption, self.lineno) caption_node = nodes.caption(caption, '', *inodes) figure_node += caption_node return [figure_node]
def run(self): node = plantuml(self.block_text, **self.options) node['uml'] = '\n'.join(self.content) # XXX maybe this should be moved to _visit_plantuml functions. it # seems wrong to insert "figure" node by "plantuml" directive. if 'caption' in self.options or 'align' in self.options: node = nodes.figure('', node) if 'align' in self.options: node['align'] = self.options['align'] if 'caption' in self.options: import docutils.statemachine cnode = nodes.Element() # anonymous container for parsing sl = docutils.statemachine.StringList([self.options['caption']], source='') self.state.nested_parse(sl, self.content_offset, cnode) caption = nodes.caption(self.options['caption'], '', *cnode) node += caption return [node]
def run(self): node = plantuml(self.block_text, **self.options) node["uml"] = "\n".join(self.content) # XXX maybe this should be moved to _visit_plantuml functions. it # seems wrong to insert "figure" node by "plantuml" directive. if "caption" in self.options or "align" in self.options: node = nodes.figure("", node) if "align" in self.options: node["align"] = self.options["align"] if "caption" in self.options: import docutils.statemachine cnode = nodes.Element() # anonymous container for parsing sl = docutils.statemachine.StringList([self.options["caption"]], source="") self.state.nested_parse(sl, self.content_offset, cnode) caption = nodes.caption(self.options["caption"], "", *cnode) node += caption return [node]
def figure(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): figwidth = options.setdefault('figwidth') figclass = options.setdefault('figclass') del options['figwidth'] del options['figclass'] (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: # PIL doesn't like Unicode paths: try: i = Image.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclass: figure_node.set_class(figclass) 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 build_node(self): srclang = self.arguments[0].strip() if srclang not in RENDER_MARKUP_EXT.keys(): return [self.state_machine.reporter.warning( 'Unknown source language "%s", use one of: %s.' % ( srclang, ",".join(RENDER_MARKUP_EXT.keys())), line=self.lineno)] code = '\n'.join(self.content) if not code.strip(): return [self.state_machine.reporter.warning( 'Ignoring "%s" directive without content.' % ( self.name), line=self.lineno)] node = kernel_render() node['alt'] = self.options.get('alt','') node['srclang'] = srclang literal_node = nodes.literal_block(code, code) node += literal_node caption = self.options.get('caption') if caption: # parse caption's content parsed = nodes.Element() self.state.nested_parse( ViewList([caption], source=''), self.content_offset, parsed) caption_node = nodes.caption( parsed[0].rawsource, '', *parsed[0].children) caption_node.source = parsed[0].source caption_node.line = parsed[0].line figure_node = nodes.figure('', node) for k,v in self.options.items(): figure_node[k] = v figure_node += caption_node node = figure_node return node
def _make_figure_node(self, *children): # Build figure node. if isinstance(children[0], nodes.system_message): return children[:1] figure_node = nodes.figure('', *children) # Pop options. figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) # Figure property "figwidth". if figwidth: figure_node['width'] = figwidth # Figure property "figclass". if figclasses: figure_node['classes'] += figclasses # Figure property "align". if align: figure_node['align'] = align # Figure property "caption". Only valid when texpath is used. if self.content: node = nodes.Element() # Anonymous container for parsing. self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def _make_figure_node(self, *children): # Build figure node. if isinstance(children[0], nodes.system_message): return children[:1] figure_node = nodes.figure('', *children) # Pop options. figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) # Figure property "figwidth". if figwidth: figure_node['width'] = figwidth # Figure property "figclass". if figclasses: figure_node['classes'] += figclasses # Figure property "align". if align: figure_node['align'] = align # Figure property "caption". Only valid when texpath is used. if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def test_process_doc_handle_figure_caption(): env = mock.Mock(domaindata={}) env.app.registry.enumerable_nodes = {} figure_node = nodes.figure( '', nodes.caption('caption text', 'caption text'), ) document = mock.Mock( nametypes={'testname': True}, nameids={'testname': 'testid'}, ids={'testid': figure_node}, citation_refs={}, ) document.traverse.return_value = [] domain = StandardDomain(env) if 'testname' in domain.data['labels']: del domain.data['labels']['testname'] domain.process_doc(env, 'testdoc', document) assert 'testname' in domain.data['labels'] assert domain.data['labels']['testname'] == ( 'testdoc', 'testid', 'caption text')
def run(self): warning = self.state.document.reporter.warning env = self.state.document.settings.env if self.arguments and self.content: return [warning('uml directive cannot have both content and ' 'a filename argument', line=self.lineno)] if self.arguments: fn = search_image_for_language(self.arguments[0], env) relfn, absfn = env.relfn2path(fn) env.note_dependency(relfn) try: umlcode = _read_utf8(absfn) except (IOError, UnicodeDecodeError) as err: return [warning('PlantUML file "%s" cannot be read: %s' % (fn, err), line=self.lineno)] else: relfn = env.doc2path(env.docname, base=None) umlcode = '\n'.join(self.content) node = plantuml(self.block_text, **self.options) node['uml'] = umlcode node['incdir'] = os.path.dirname(relfn) # XXX maybe this should be moved to _visit_plantuml functions. it # seems wrong to insert "figure" node by "plantuml" directive. if 'caption' in self.options or 'align' in self.options: node = nodes.figure('', node) if 'align' in self.options: node['align'] = self.options['align'] if 'caption' in self.options: import docutils.statemachine cnode = nodes.Element() # anonymous container for parsing sl = docutils.statemachine.StringList([self.options['caption']], source='') self.state.nested_parse(sl, self.content_offset, cnode) caption = nodes.caption(self.options['caption'], '', *cnode) node += caption return [node]
def test_process_doc_handle_figure_caption(): env = mock.Mock(domaindata={}) env.app.registry.enumerable_nodes = {} figure_node = nodes.figure( '', nodes.caption('caption text', 'caption text'), ) document = mock.Mock( nametypes={'testname': True}, nameids={'testname': 'testid'}, ids={'testid': figure_node}, citation_refs={}, ) document.traverse.return_value = [] domain = StandardDomain(env) if 'testname' in domain.data['labels']: del domain.data['labels']['testname'] domain.process_doc(env, 'testdoc', document) assert 'testname' in domain.data['labels'] assert domain.data['labels']['testname'] == ('testdoc', 'testid', 'caption text')
def apply(self): for image in self.document.traverse(nodes.image): # skip inline images # (See also: class `TextElement` in `docutils.nodes`.) if isinstance(image.parent, nodes.TextElement): continue # wrap all block images into figures if isinstance(image.parent, nodes.figure): figure = image.parent else: figure = nodes.figure() figure['float'] = ('none', ) # do not float bare images figure['width'] = image.attributes.get('width', 'image') figure['align'] = image.attributes.get('align', 'center') image['width'] = '100%' image.replace_self(figure) figure.append(image) # set default width, align for block images only image.setdefault('width', '100%') image.setdefault('align', 'center')
def run(self): grid_node = nodes.container() grid_node['classes'] += ['m-imagegrid', 'm-container-inflate'] rows = [[]] total_widths = [0] for uri_caption in self.content: # New line, calculating width from 0 again if not uri_caption: rows.append([]) total_widths.append(0) continue uri, _, caption = uri_caption.partition(' ') # Open the files and calculate the overall width # Support both {filename} (3.7.1) and {static} (3.8) placeholders, # also prepend the absolute path in case we're not Pelican file = os.path.join(os.getcwd(), settings['INPUT']) absuri = os.path.join(file, uri.format(filename=file, static=file)) im = PIL.Image.open(absuri) # If no caption provided, get EXIF info, if it's there if not caption and hasattr(im, '_getexif') and im._getexif() is not None: exif = { PIL.ExifTags.TAGS[k]: v for k, v in im._getexif().items() if k in PIL.ExifTags.TAGS and len(str(v)) < 256 } # Not all info might be present caption = [] if 'FNumber' in exif: caption += ["F{}".format(float(float(exif['FNumber'][0])/float(exif['FNumber'][1])))] if 'ExposureTime' in exif: numerator, denominator = exif['ExposureTime'] if int(numerator) > int(denominator): caption += ["{} s".format(float(numerator)/float(denominator))] else: caption += ["{}/{} s".format(numerator, denominator)] if 'ISOSpeedRatings' in exif: caption += ["ISO {}".format(exif['ISOSpeedRatings'])] caption = ', '.join(caption) # If the caption is `..`, it's meant to be explicitly disabled if caption == '..': caption = '' rel_width = float(im.width)/im.height total_widths[-1] += rel_width rows[-1].append((uri, rel_width, caption)) for i, row in enumerate(rows): row_node = nodes.container() for uri, rel_width, caption in row: image_reference = rst.directives.uri(uri) image_node = nodes.image('', uri=image_reference) # <figurecaption> in case there's a caption if caption: text_nodes, _ = self.state.inline_text(caption, self.lineno) text_node = nodes.paragraph('', '', *text_nodes) overlay_node = nodes.caption() overlay_node.append(text_node) # Otherwise an empty <div> else: overlay_node = nodes.container() link_node = nodes.reference('', refuri=image_reference) link_node.append(image_node) link_node.append(overlay_node) wrapper_node = nodes.figure(width="{:.3f}%".format(rel_width*100.0/total_widths[i])) wrapper_node.append(link_node) row_node.append(wrapper_node) grid_node.append(row_node) return [grid_node]
def _render_image(output: NotebookNode, index: int): # Sphinx treats absolute paths as being rooted at the source # directory, so make a relative path, which Sphinx treats # as being relative to the current working directory. filename = os.path.basename(output.metadata["filenames"][mime_type]) # checks if file dir path is inside a subdir of dir filedir = os.path.dirname(output.metadata["filenames"][mime_type]) subpaths = filedir.split(self.sphinx_dir) final_dir = self.sphinx_dir if subpaths and len(subpaths) > 1: subpath = subpaths[1] final_dir += subpath uri = os.path.join(final_dir, filename) # TODO I'm not quite sure why, but as soon as you give it a width, # it becomes clickable?! (i.e. will open the image in the browser) image_node = nodes.image(uri=uri) myst_meta_img = self.node.metadata.get( self.env.config.nb_render_key, {} ).get("image", {}) for key, spec in [ ("classes", directives.class_option), ("alt", directives.unchanged), ("height", directives.length_or_unitless), ("width", directives.length_or_percentage_or_unitless), ("scale", directives.percentage), ("align", align), ]: if key in myst_meta_img: value = myst_meta_img[key] try: image_node[key] = spec(value) except (ValueError, TypeError) as error: error_msg = ( "Invalid image attribute: " "(key: '{}'; value: {})\n{}".format(key, value, error) ) return [self.make_error(error_msg)] myst_meta_fig = self.node.metadata.get( self.env.config.nb_render_key, {} ).get("figure", {}) if "caption" not in myst_meta_fig: return [image_node] figure_node = nodes.figure("", image_node) caption = nodes.caption(myst_meta_fig["caption"], "") figure_node += caption # TODO only contents of one paragraph? (and second should be a legend) self.parse_markdown(myst_meta_fig["caption"], caption) if "name" in myst_meta_fig: name = myst_meta_fig["name"] self.add_source_and_line(figure_node) self.add_name(figure_node, name) # The target should have already been processed by now, with # sphinx.transforms.references.SphinxDomains, which calls # sphinx.domains.std.StandardDomain.process_doc, # so we have to replicate that here std = self.env.get_domain("std") nametypes = self.document.nametypes.items() self.document.nametypes = {name: True} try: std.process_doc(self.env, self.env.docname, self.document) finally: self.document.nametypes = nametypes return [figure_node]