Esempio n. 1
0
def action(elem, doc):
    if isinstance(elem, panflute.CodeBlock) and 'graphviz' in elem.classes:
        svg = check_output(GRAPHVIZ_COMMAND, input=elem.text.encode('utf8'))
        b64data = b64encode(svg).decode('utf8')
        url = 'data:image/svg+xml;base64,{}'.format(b64data)
        return panflute.Para(panflute.Image(url=url))
    elif isinstance(elem, panflute.CodeBlock) and 'uml' in elem.classes:
        svg = check_output(PLANTUML_COMMAND, input=elem.text.encode('utf8'))
        b64data = b64encode(svg).decode('utf8')
        url = 'data:image/svg+xml;base64,{}'.format(b64data)
        return panflute.Para(panflute.Image(url=url))
Esempio n. 2
0
def sage(elem, doc):
    elemtype = type(elem)

    if elemtype in [pf.Math, pf.RawInline]:
        contents = replace_sagecommand(elem.text)

        if elemtype == pf.Math:
            return pf.Math(contents, format=elem.format)
        else:
            return pf.RawInline(contents, format=elem.format)

    if elemtype == pf.CodeBlock:

        isSageSilent = 'sagesilent' in elem.classes
        isSageBlock = 'sageblock' in elem.classes
        isSagePlot = 'sageplot' in elem.classes

        code = elem.text
        if isSageBlock or isSagePlot or isSageSilent:
            img_file = get_image_output_filename(code)
            sage_file = get_sage_filename(code)

            if isSagePlot:
                code = code.strip("\n")
                codelist = code.split("\n")
                plot_cmd = codelist.pop()
                code = "\n".join(codelist)
                m = re.search(r"sageplot\[(?P<first_name>.*)\]\((.*)\)",
                              plot_cmd)
                if m == None:
                    para, cmd = "", plot_cmd
                else:
                    para, cmd = m.group(1), m.group(2)
                if len(para) > 0:
                    para = ',' + para
                code += "\n(%s).save(\"%s\"%s)" % (cmd, img_file, para)

            out, err = run_sage(code)

            if isSageSilent:
                return pf.Plain(pf.RawInline("", "tex"))
            elif isSageBlock:
                sys.stderr.write('\n convert markdown \n')
                return pf.convert_text(out)
            else:
                return pf.Para(
                    pf.Image(url=img_file, attributes=elem.attributes))
        if 'latex' in elem.classes:
            out, err, img_file = run_tex(code)

            return pf.Para(pf.Image(url=img_file, attributes=elem.attributes))
Esempio n. 3
0
    def figure(self, options, data, element, doc):

        # pf.debug(doc.get_metadata("include", "no hoge"))
        # pf.debug(element.attributes)
        # pf.debug(element.parent)
        # pf.debug("prev", element.prev)
        # pf.debug(element)
        # pf.debug("next", element.next)
        # Para(
        #     Image(
        #         Strong(Str(caption));
        #         url="../images/front-image.png",
        #         title="fig:",
        #         attributes=OrderedDict([("width", "50%")])
        #     )
        # )

        # Get options
        fn = options.get("source")
        pf.debug("rotate image of", fn)
        fn = os.path.abspath(fn).replace("\\", "/")
        title = options.get("title", "fig:")
        caption = options.get("caption")
        label = options.get("label", os.path.splitext(os.path.basename(fn))[0])
        angle = options.get("angle", 0)
        attr = options.get("attr", {})

        # pf.debug(attr)

        fn = self.rotate(fn, angle)
        title = pf.convert_text(title)

        if not attr:
            attr = OrderedDict({})

        # assert len(title) == 1, title

        title = title[0]
        title_text = pf.stringify(title).strip()

        # pf.debug(caption)
        if caption:
            caption = pf.convert_text(caption)
            caption = caption[0].content
            img = pf.Image(*caption, url=fn, title=title_text, attributes=attr)
        else:
            img = pf.Image(url=fn, attributes=attr)
        ans = pf.Para(img)
        # pf.debug("ans", ans)
        return ans
Esempio n. 4
0
 def do_image(self, elem):
     old_url = elem.url
     basename = os.path.basename(old_url)
     dirname = os.path.dirname(old_url)
     parts = os.path.normpath(dirname).split(os.sep)
     first_seg = parts[0]
     if "http" in first_seg:
         return elem
     image_key = ""
     #  for ik in ["image", "images"]:
     #  if ik not in parts:
     #  continue
     #  image_key = ik
     #  break
     for part in parts:
         if part in ["image", "images"]:
             image_key = part
             break
     if image_key == "":
         return elem
     sep_idx = parts.index(image_key) + 1
     find_parts = parts[:sep_idx]
     rest_parts = parts[sep_idx:]
     new_dir = self.find_image_dir(find_parts)
     if new_dir is None:
         return elem
     new_parts = [new_dir] + rest_parts + [basename]
     new_url = os.path.join(*new_parts)
     return pf.Image(pf.Str(elem.title), url=new_url)
Esempio n. 5
0
def graphviz_filter(elem, doc):
    if isinstance(elem, pf.CodeBlock) and 'graphviz' in elem.classes:
        code = elem.text
        graph = pygraphviz.AGraph(string=code)
        title = graph.graph_attr.pop('label', '')
        graph.layout()
        path = gen_randpath()
        graph.draw(path, prog='dot')
        para = pf.Para(pf.Image(pf.Str(title), title='fig:', url=path))
        return para
    def action(self, elem, doc):
        if isinstance(elem, pf.Link) and (("wavedrom" in elem.classes) or
                                          ("bitfield" in elem.classes)):
            fn = elem.url
            options = elem.attributes
            idn = elem.identifier
            caption = elem.content
            with open(fn, "r", encoding="utf-8") as f:
                data = f.read()
                data = self.validatejson(data)

            self.get_options(options, data, elem, doc)
            assert self.source is not None, "mandatory option input is not set"
            assert os.path.exists(
                self.source) == 1, "input file does not exist"
            assert isinstance(self.convert_to_png,
                              bool), "option png is boolean"
            assert isinstance(self.convert_to_pdf,
                              bool), "option pdf is boolean"
            assert isinstance(self.convert_to_eps,
                              bool), "option eps is boolean"

            output = wavedrom.render(data, self.svg_filename)
            output.saveas(self.svg_filename)
            # pf.debug(output.tostring())

            self.render_images()

            pf.debug("[inline] generate wavedrom from", self.linkto)
            # pf.debug(elem)
            try:
                elem.classes.remove("wavedrom")
            except:
                elem.classes.remove("bitfield")

            elem = pf.Image(*caption,
                            classes=elem.classes,
                            url=self.linkto,
                            identifier=idn,
                            title="fig:",
                            attributes=elem.attributes)
            # pf.debug(elem)

            return elem

        if isinstance(elem, pf.Image) and "wavedrom" in elem.classes:
            pf.debug("#")
            pf.debug(
                "# Inline wavedrom in image link syntax, which is *obsolete*, is detected."
            )
            pf.debug(
                "# Use hyperlink syntax from now - Just remove ! in front.")
            pf.debug("# Removing link for safety.")
            pf.debug("#")
            return []
Esempio n. 7
0
def replace_mermaid_blocks_with_images(doc):
    """Replaces all mermaid code blocks with image blocks. Then saves the markdown content as a new file.

    Args:
        doc (panflute.Doc): Pandoc document container, has a mermaid attribute, where the  code block \
            index and image path are stored.

    """
    logger.info("Replacing mermaid code blocks with image blocks.")
    for mermaid_block_index, image_path in doc.mermaid.items():
        logger.debug(f"Replacing mermaid block {doc.content.list[mermaid_block_index]}.")
        image_element = panflute.Para(panflute.Image(panflute.Str("Image"), url=image_path))
        doc.content.list[mermaid_block_index] = image_element
Esempio n. 8
0
    def test_remember(self):
        """It should remember and forget."""
        doc = pf.Doc()

        self.assertIsNone(get_remembered(doc, "somekey"))

        header = pf.Header()
        remember(doc, "header", header)
        rememembered_el = get_remembered(doc, "header")
        self.assertEqual(rememembered_el, header)
        self.assertIsNone(get_remembered(doc, "header"))

        img = pf.Image()
        remember(doc, "img", img)
        rememembered_img = get_remembered(doc, "img")
        self.assertEqual(rememembered_img, img)
        self.assertIsNone(get_remembered(doc, "img"))
Esempio n. 9
0
    def generate(self, options, data, element, doc):
        # pf.debug("generate()")

        self.get_options(options, data, element, doc)

        assert self.source is not None, "mandatory option input is not set"
        assert os.path.exists(self.source) == 1, "input file does not exist"
        assert isinstance(self.convert_to_png, bool), "option png is boolean"
        assert isinstance(self.convert_to_pdf, bool), "option pdf is boolean"
        assert isinstance(self.convert_to_eps, bool), "option eps is boolean"

        self.json2svg()
        self.render_images()

        if not self.attr:
            attr = OrderedDict({})

        caption = pf.convert_text(self.caption)
        title = pf.convert_text(self.title)
        title = title[0]
        title_text = pf.stringify(title).strip()

        caption = caption[0]
        caption = caption.content

        # pf.debug(caption)
        # pf.debug(linkto)
        # pf.debug(title_text)
        # pf.debug(label)
        # pf.debug(attr)
        pf.debug("generate bitfield from", self.linkto)
        # img = pf.Image(*caption, url=self.linkto, identifier=elem.identifier, title="fig:", attributes=attr)
        element.classes.remove("bitfield")
        img = pf.Image(*caption,
                       classes=element.classes,
                       url=self.linkto,
                       identifier=element.identifier,
                       title="fig:",
                       attributes=element.attributes)
        # pf.debug(img)
        ans = pf.Para(img)
        # pf.debug(ans)

        return ans
Esempio n. 10
0
def proc_image(elm, doc):
    if type(elm) == pf.CodeBlock and 'image' in elm.classes:
        attr = elm.attributes

        altstr = attr.get('alt', 'an image')
        if 'alt' in attr:
            del attr['alt']
        title = attr.get('title', 'an image')
        if 'title' in attr:
            del attr['title']

        url = elm.text.strip()
        sys.stderr.write('image #' + elm.identifier + 'url=' + url + '\n')
        return pf.Para(
            pf.Image(pf.Str(altstr),
                     url=url,
                     title=title,
                     identifier=elm.identifier,
                     classes=elm.classes,
                     attributes=attr))
Esempio n. 11
0
def graphviz(elem, doc):
    if isinstance(elem, pf.CodeBlock) and 'graphviz' in elem.classes:
        code = elem.text
        G = pygraphviz.AGraph(string=code)
        G.layout(prog='dot')

        filename = sha1(code)
        filetype = {'html': 'png', 'latex': 'pdf'}.get(doc.format, 'png')
        caption = elem.attributes.get('caption', '')
        imagedir = f'{MD_DIR}/graphviz-images'
        src = f'{imagedir}/{filename}.{filetype}'
        if not os.path.isfile(src):
            try:
                os.mkdir(imagedir)
                sys.stderr.write(f'Created directory {imagedir}\n')
            except OSError:
                pass
            G.draw(src)
            sys.stderr.write(f'Created image {src}\n')
        return pf.Para(pf.Image(pf.Str(caption), url=src, title=caption))
Esempio n. 12
0
def figure(options, data, element, doc):

    # Get options
    fn = os.path.abspath(options['source']).replace('\\', '/')
    title = options.get('title', 'Untitled')
    notes = data
    label = options.get('label', os.path.splitext(os.path.basename(fn))[0])

    if doc.format == 'latex':
        subs = {'fn': fn, 'label': label}
        subs['title'] = pf.convert_markdown(title, format='latex')
        subs['notes'] = pf.convert_markdown(notes, format='latex')
        backmatter = doc.get_metadata('format.backmatter', False)
        pagebreak = doc.get_metadata('format.media-pagebreak', False)

        w = options.get('width', 1.0)
        subs['width'] = w
        subs['innerwidth'] = options.get('innerwidth', w) / w
        subs['notesize'] = options.get('notesize', 'small')
        subs['pagebreak'] = '\\clearpage\n' if pagebreak else ''

        text = LATEX_TEMPLATE.safe_substitute(subs)
        ans = pf.RawBlock(text=text, format='latex')

        if backmatter:
            doc.backmatter.append(ans)
            msg = '\hyperref[fig:{}]{{[\Cref{{fig:{}}} Goes Here]}}'
            msg = msg.format(label, label)
            return pf.Plain(pf.Str(msg))
        else:
            return ans
    else:
        title = pf.convert_markdown(title)
        assert len(title)==1, title
        title = (title[0]).items

        notes = pf.Div(*pf.convert_markdown(notes), classes=['note'])
        title_text = pf.stringify(title)
        img = pf.Image(*title, url=fn, title=title_text, identifier=label)
        ans = pf.Div(pf.Plain(img), pf.Plain(pf.LineBreak), notes, classes=['figure'])
        return ans
Esempio n. 13
0
def create_image(filename, descr, elem, add_descr=True, block=True):
    """Create an image element."""

    img = pf.Image(url=filename, classes=ELEMENT_CLASSES["IMAGE"])

    if add_descr:
        descr = parse_fragment(descr, elem.doc.metadata["lang"].text, as_doc=True)
        img.title = shorten(
            pf.stringify(*descr.content).strip(), width=125, placeholder="..."
        )
    else:
        img.title = descr

    if block:
        ret = pf.Div(pf.Plain(img), classes=ELEMENT_CLASSES["FIGURE"])
        remember(elem.doc, "label", ret)
        if add_descr:
            ret.content.append(descr.content[0])
    else:
        remember(elem.doc, "label", img)
        ret = img

    return ret
Esempio n. 14
0
def mermaid(elem, doc):
    if isinstance(elem, pf.CodeBlock) and 'mermaid' in elem.classes:
        code = elem.text
        caption = elem.attributes.get('caption', '')
        filename = sha1(code)

        mermaid_dir = f'{MD_DIR}/mermaid-images'
        src_file = f'{mermaid_dir}/{filename}.mmd'
        dst_img = f'{mermaid_dir}/{filename}.svg'
        if not os.path.isfile(src_file):
            try:
                os.mkdir(mermaid_dir)
                sys.stderr.write(f'Created directory {mermaid_dir}\n')
            except OSError:
                pass

            with open(src_file, 'w') as f:
                f.write(code)

            subprocess.check_call(['mmdc', '-i', src_file, '-o', dst_img],
                                  stderr=subprocess.DEVNULL,
                                  stdout=subprocess.DEVNULL)
        return pf.Para(pf.Image(pf.Str(caption), url=dst_img, title=caption))
Esempio n. 15
0
    def render(self, options, data, element, doc):
        self.doc = doc
        self.source = options.get("input")
        self.toPNG = bool(options.get("png", True))
        self.toSVG = bool(options.get("svg", False))
        self.toPDF = True if doc.format in ["latex"] else bool(
            options.get("pdf", False))
        self.caption = options.get("caption", "Untitled")
        self.dir_to = options.get("directory", self.defaultdir_to)

        if os.path.exists(self.dir_to) != 1:
            os.mkdir(self.dir_to)

        self.counter = hashlib.sha1(data.encode("utf-8")).hexdigest()[:8]
        self.basename = "/".join([self.dir_to, str(self.counter)])

        if not self.source and data is not None:
            # pf.debug("not source and data is not None")
            self.source = ".".join([self.basename, "txt"])
            code = data
            open(self.source, "w", encoding="utf-8").write(data)
        else:  # source and data is "dont care"
            code = open(self.source, "r", encoding="utf-8").read()

        assert self.source is not None, "option input is mandatory"
        assert isinstance(self.toPNG, bool), "option png is boolean"
        assert isinstance(self.toPDF, bool), "option pdf is boolean"

        self.svg = ".".join([self.basename, "svg"])
        self.png = ".".join([self.basename, "png"])
        self.pdf = ".".join([self.basename, "pdf"])
        aafigure.render(code, self.svg, {"format": "svg"})

        if (self.toPDF):
            aafigure.render(code, self.pdf, {"format": "pdf"})

        if (self.toPNG):
            aafigure.render(code, self.png, {"format": "png"})

        # options = {
        #     "format": filetype,
        # }
        if self.doc.format in ["latex"]:
            linkto = self.pdf
        elif self.doc.format in ["html", "html5"]:
            linkto = self.svg
        else:
            if not (self.toPNG):
                aafigure.render(code, self.png, {"format": "png"})
            linkto = self.png

        caption = pf.convert_text(self.caption)
        caption = caption[0]
        caption = caption.content

        render_message = " ".join(["generate aafigure from", linkto])
        self.render_message = render_message if not self.render_message else " ".join(
            [self.render_message, linkto])
        pf.debug(self.render_message)
        element.classes.remove("aafigure")
        linkto = os.path.abspath(linkto).replace("\\", "/")
        img = pf.Image(*caption,
                       classes=element.classes,
                       url=linkto,
                       identifier=element.identifier,
                       title="fig:",
                       attributes=element.attributes)
        # pf.debug(img)
        ans = pf.Para(img)
        # pf.debug(ans)

        return ans
Esempio n. 16
0
    def convert(self):
        doc = panflute.Doc(
            api_version=(1, 17, 5),
            metadata={
                'pagetitle': self.title,
            },
        )

        doc.content.append(panflute.Header(panflute.Str(self.title)))

        lists = {}
        tables = {}
        table_rows = {}
        table_cells = {}

        for chunk in self._attr_chunks():
            self.logger.debug(chunk)
            container = panflute.Para()
            cdiv = panflute.Div(container)

            # Handle lists
            if 'list_class' in chunk[0]['attrs']:
                lc = chunk[0]['attrs']['list_class']
                check_state = None
                if lc in ['checked', 'unchecked']:
                    check_state = lc
                    lc = 'checklist'
                ld = chunk[0]['attrs']['list_depth']

                # prune any lists that are lower than us, they're finished
                for i in list(lists.keys()):
                    if i > ld:
                        lists.pop(i)

                # non-homogenous list types can be immediately adjacent without
                # ending up merged
                if ld in lists and lists[ld]['class'] != lc:
                    lists.pop(ld)

                # checklists are a special case, they can't contain other lists
                if lc != 'checklist' and lists and lists[1][
                        'class'] == 'checklist':
                    lists = {}

                # make sure any intermediate lists were created, including
                # the top level because boxnotes
                for i in range(1, ld + 1):
                    if i not in lists:
                        lists[i] = self._list(lc, i)
                        if i != ld:
                            lists[i]['pf'].content.append(panflute.ListItem())
                        lp = lists[i]['pf']
                        if lc == 'checklist':
                            lp = panflute.Div(lp, classes=['checklist'])
                        if i == 1:
                            doc.content.append(lp)
                        else:
                            lists[i - 1]['pf'].content[-1].content.append(lp)

                # set the container for the other subchunks
                container = panflute.Plain()
                cdiv.content = [container]
                cdiv.classes.append(lc)
                if check_state:
                    cdiv.classes.append(check_state)
                lists[ld]['pf'].content.append(panflute.ListItem(cdiv))

                if check_state == 'checked':
                    container.content.append(panflute.Str(CHECKED))
                elif check_state == 'unchecked':
                    container.content.append(panflute.Str(UNCHECKED))

            elif 'table_id' in chunk[-1]['attrs']:
                table_id = chunk[-1]['attrs']['table_id']
                row_id = chunk[-1]['attrs']['table_row']
                cell_id = row_id + chunk[-1]['attrs']['table_col']

                if table_id not in tables:
                    # There's some magic in the constructor for panflute tables
                    # that isn't exposed in any other way, so we can't create
                    # the table until we've finished populating the rows.
                    # Instead, use a placeholder div to locate it within the
                    # document.
                    tables[table_id] = {
                        'div': panflute.Div(),
                        'rows': [],
                    }
                    doc.content.append(tables[table_id]['div'])
                if row_id not in table_rows:
                    table_rows[row_id] = panflute.TableRow()
                    tables[table_id]['rows'].append(table_rows[row_id])
                if cell_id not in table_cells:
                    cdiv = panflute.Div(panflute.Plain())
                    table_cells[cell_id] = panflute.TableCell(cdiv)
                    table_rows[row_id].content.append(table_cells[cell_id])
                container = table_cells[cell_id].content[0].content[0]

            else:
                lists = {}
                doc.content.append(cdiv)

            if 'align' in chunk[0]['attrs']:
                cdiv.attributes['style'] = 'text-align: ' + chunk[0]['attrs'][
                    'align'] + ';'

            for subchunk in chunk:
                if subchunk['newlines'] > 1:
                    # we've had an extra linebreak, no more adding on to lists
                    lists = {}

                # don't do anything with markers
                if subchunk['text'] == '*' and 'lmkr' in subchunk['attrs']:
                    continue

                scont = container
                if 'href' in subchunk['attrs']:
                    scont = panflute.Link(url=subchunk['attrs']['href'])
                    container.content.append(scont)

                if 'image' in subchunk['attrs']:
                    scont.content.append(
                        panflute.Image(
                            url=self._image(subchunk['attrs']['author'],
                                            subchunk['attrs']['image'])))
                    continue

                span = panflute.Span()
                lines = subchunk['text'].splitlines()
                while lines:
                    subtext = lines.pop(0)
                    span.content.append(panflute.Str(subtext))
                    if lines:
                        span.content.append(panflute.LineBreak())

                if 'font' in subchunk['attrs']:
                    color = subchunk['attrs']['font'].get('color', '000000')
                    size = subchunk['attrs']['font'].get('size', 'medium')
                    span.classes.append('font-size-' + size)
                    span.classes.append('font-color-' + color)

                    # I don't actually know what the possible colors are and I
                    # don't feel like finding out, so just inject it as an
                    # inline style.
                    if color != '000000':
                        span.attributes['style'] = 'color: #' + color + ';'

                if subchunk['attrs'].get('underline'):
                    span.classes.append('underline')
                if subchunk['attrs'].get('bold'):
                    span = panflute.Strong(span)
                if subchunk['attrs'].get('italic'):
                    span = panflute.Emph(span)
                if subchunk['attrs'].get('strikethrough'):
                    span = panflute.Strikeout(span)
                scont.content.append(span)

        # Actually create the tables
        for x in tables:
            tables[x]['div'].content.append(panflute.Table(*tables[x]['rows']))

        with io.StringIO() as f:
            panflute.dump(doc, f)
            return f.getvalue()
Esempio n. 17
0
 def run(self):
     url = self.renderer(self.input, self.cmd_renderer)
     pfcaption = (pf.convert_text(self.caption))[0].content
     return pf.Para(
         pf.Image(*pfcaption, url=url, title=u'fig:' + self.caption))
Esempio n. 18
0
    def action(self, elem, doc):
        if isinstance(elem, pf.Link) and "svgbob" in elem.classes:
            fn = elem.url
            options = elem.attributes
            caption = elem.content

            meta_font_family = doc.get_metadata("svgbob.font-family", "Arial")
            meta_font_size = doc.get_metadata("svgbob.font-size", 14)
            meta_scale = doc.get_metadata("svgbob.scale", 1)
            meta_stroke_width = doc.get_metadata("svgbob.stroke-width", 2)

            font_family = options.get("font-family", meta_font_family)
            font_size = options.get("font-size", meta_font_size)
            scale = options.get("scale", meta_scale)
            stroke_width = options.get("stroke-width", meta_stroke_width)
            svgbob_option = " ".join([
                '--font-family "{}"'.format(font_family)
                if font_family is not None else "",
                "--font-size {}".format(font_size)
                if font_size is not None else "",
                "--scale {}".format(scale) if scale is not None else "",
                "--stroke-width {}".format(stroke_width)
                if stroke_width is not None else "",
            ])
            if not os.path.exists(self.dir_to):
                os.mkdir(self.dir_to)

            data = open(fn, "r", encoding="utf-8").read()
            counter = hashlib.sha1(data.encode("utf-8")).hexdigest()[:8]
            self.basename = "/".join([self.dir_to, str(counter)])

            _format = "svg"
            # if doc.format in ["latex"]:
            #     format = "pdf"
            # elif doc.format in ["html", "html5"]:
            #     format = "svg"
            # else:
            #     format = "png"

            fn = os.path.abspath(fn)
            linkto = os.path.abspath(".".join([self.basename,
                                               _format])).replace("\\", "/")

            command = "svgbob {} {} -o {}".format(fn, svgbob_option, linkto)
            pf.debug(command)
            sp.Popen(command,
                     shell=True,
                     stdin=sp.PIPE,
                     stdout=sp.PIPE,
                     stderr=sp.PIPE)

            pf.debug("[inline] generate svgbob from {} to {}".format(
                fn, linkto))
            elem.classes.remove("svgbob")
            elem = pf.Image(*caption,
                            classes=elem.classes,
                            url=linkto,
                            identifier=elem.identifier,
                            title="fig:",
                            attributes=elem.attributes)

            # pf.debug(elem)

            return elem