Example #1
0
 def append_font(self, fontfamily, path):
     _path, _ = parse_fontpath(path)
     if path is None or os.path.isfile(_path):
         font = FontInfo(fontfamily, path, self.fontsize)
         self.fonts[font.familyname] = font
     else:
         warning('fontfile `%s` is not found: %s', fontfamily, path)
Example #2
0
def open(url, mode='Pillow'):
    if hasattr(url, 'read') or isinstance(url, Image.Image):
        stream = url
    elif not urlutil.isurl(url):
        stream = io.open(url, 'rb')
    else:
        try:
            # wrap BytesIO for rewind stream
            stream = io.BytesIO(urlopen(url).read())
        except:
            warning(u("Could not retrieve: %s"), url)
            raise IOError

    image = pillow_open(url, stream)
    if mode.lower() == 'pillow':
        # stream will be closed by GC
        return image
    else:  # mode == 'png'
        try:
            png_image = io.BytesIO()
            image.save(png_image, 'PNG')
            if hasattr(stream, 'close'):  # close() is implemented on Pillow
                stream.close()
        except:
            warning(u("Could not convert image: %s"), url)
            raise IOError

        png_image.seek(0)
        return png_image
Example #3
0
 def append_font(self, fontfamily, path):
     _path, _ = parse_fontpath(path)
     if path is None or os.path.isfile(_path):
         font = FontInfo(fontfamily, path, self.fontsize)
         self.fonts[font.familyname] = font
     else:
         warning("fontfile `%s` is not found: %s", fontfamily, path)
Example #4
0
    def on_background_changing(self, node, value):
        formula_env = self.get_formula_env(value)
        if formula_env is None:  # not math uri
            return True

        warning('background = "math://..." is deprecated. '
                'use label attribute.')
        return self.set_formula_image_to_background(node, value, formula_env)
Example #5
0
def init_imagedrawers(debug=False):
    for drawer in pkg_resources.iter_entry_points('blockdiag_imagedrawers'):
        try:
            module = drawer.load()
            if hasattr(module, 'setup'):
                module.setup(module)
        except Exception as exc:
            if debug:
                warning('Failed to load %s: %r' % (drawer.module_name, exc))
Example #6
0
    def validate(self):
        if len(self.args) == 0:
            self.parser.print_help()
            sys.exit(0)

        self.options.input = self.args.pop(0)
        if self.options.output:
            pass
        elif self.options.output == '-':
            self.options.output = 'output.' + self.options.type.lower()
        else:
            basename = os.path.splitext(self.options.input)[0]
            ext = '.%s' % self.options.type.lower()
            self.options.output = basename + ext

        self.options.type = self.options.type.upper()
        try:
            imagedraw.create(self.options.type, None, debug=self.options.debug)
        except:
            msg = "unknown format: %s" % self.options.type
            raise RuntimeError(msg)

        if self.options.size:
            matched = re.match('^(\d+)x(\d+)$', self.options.size)
            if matched:
                self.options.size = [int(n) for n in matched.groups()]
            else:
                msg = "--size option must be formatted as WIDTHxHEIGHT."
                raise RuntimeError(msg)

        if self.options.type == 'PDF':
            try:
                import reportlab.pdfgen.canvas
                reportlab.pdfgen.canvas
            except ImportError:
                msg = "could not output PDF format; Install reportlab."
                raise RuntimeError(msg)

        if self.options.ignore_pil:
            warning("--ignore-pil option is deprecated "
                    "(detect automatically).")

        if self.options.nodoctype and self.options.type != 'SVG':
            msg = "--nodoctype option work in SVG images."
            raise RuntimeError(msg)

        if self.options.transparency is False and self.options.type != 'PNG':
            msg = "--no-transparency option work in PNG images."
            raise RuntimeError(msg)

        if self.options.config and not os.path.isfile(self.options.config):
            msg = "config file is not found: %s" % self.options.config
            raise RuntimeError(msg)

        if self.options.fontmap and not os.path.isfile(self.options.fontmap):
            msg = "fontmap file is not found: %s" % self.options.fontmap
            raise RuntimeError(msg)
Example #7
0
    def validate(self):
        if len(self.args) == 0:
            self.parser.print_help()
            sys.exit(0)

        self.options.input = self.args.pop(0)
        if self.options.output:
            pass
        elif self.options.output == '-':
            self.options.output = 'output.' + self.options.type.lower()
        else:
            basename = os.path.splitext(self.options.input)[0]
            ext = '.%s' % self.options.type.lower()
            self.options.output = basename + ext

        self.options.type = self.options.type.upper()
        try:
            imagedraw.create(self.options.type, None, debug=self.options.debug)
        except Exception:
            msg = "unknown format: %s" % self.options.type
            raise RuntimeError(msg)

        if self.options.size:
            matched = re.match(r'^(\d+)x(\d+)$', self.options.size)
            if matched:
                self.options.size = [int(n) for n in matched.groups()]
            else:
                msg = "--size option must be formatted as WIDTHxHEIGHT."
                raise RuntimeError(msg)

        if self.options.type == 'PDF':
            try:
                import reportlab.pdfgen.canvas
                reportlab.pdfgen.canvas
            except ImportError:
                msg = "could not output PDF format; Install reportlab."
                raise RuntimeError(msg)

        if self.options.ignore_pil:
            warning("--ignore-pil option is deprecated "
                    "(detect automatically).")

        if self.options.nodoctype and self.options.type != 'SVG':
            msg = "--nodoctype option work in SVG images."
            raise RuntimeError(msg)

        if self.options.transparency is False and self.options.type != 'PNG':
            msg = "--no-transparency option work in PNG images."
            raise RuntimeError(msg)

        if self.options.config and not os.path.isfile(self.options.config):
            msg = "config file is not found: %s" % self.options.config
            raise RuntimeError(msg)

        if self.options.fontmap and not os.path.isfile(self.options.fontmap):
            msg = "fontmap file is not found: %s" % self.options.fontmap
            raise RuntimeError(msg)
Example #8
0
    def set_edge_layout(self, value):
        value = value.lower()
        if value in ('normal', 'flowchart'):
            warning("edge_layout is very experimental feature!")

            self.edge_layout = value
        else:
            msg = "unknown edge layout: %s" % value
            raise AttributeError(msg)
Example #9
0
    def set_dir(self, value):
        params = self.ARROW_DEF.get(value.lower())
        if params is None:
            warning("unknown edge dir: %s", value)
        else:
            self.dir, self.style, self.asynchronous = params

            if self.node1 == self.node2 and self.dir in ('forward', 'back'):
                self.activate = False
Example #10
0
    def set_edge_layout(self, value):
        value = value.lower()
        if value in ('normal', 'flowchart'):
            warning("edge_layout is very experimental feature!")

            self.edge_layout = value
        else:
            msg = "unknown edge layout: %s" % value
            raise AttributeError(msg)
Example #11
0
    def on_resizable_changing(self, node, value):
        if value.lower() not in ('true', 'false'):
            warning('%s is not boolean value. ignored.' % value)

        if value.lower() == 'true':
            node.resizable = True
        else:
            node.resizable = False

        return False
Example #12
0
    def on_label_changing(self, node, value):
        formula_env = self.get_formula_env(value)
        if formula_env is None:  # not math uri
            return True

        if getattr(node, 'uses_formula_image', False):
            warning('formula has already been specified: %s' % value)
            return False

        node.label = ""
        return self.set_formula_image_to_background(node, value, formula_env)
Example #13
0
def get_image_size(options):
    image_size = options.get('size', 'normal').lower()
    try:
        r = int(image_size)
    except:
        r = image_size_def.get(image_size)
        if r is None:
            warning('unknown image size: %s', image_size)
            r = image_size_def.get('normal')

    return r
Example #14
0
    def __init__(self, diagram, **kwargs):
        super(FormulaImagePlugin, self).__init__(diagram, **kwargs)
        self.default_formula_env = kwargs.get('env', DEFAULT_ENVIRONMENT)
        self.stylepackage = None

        stylefile = kwargs.get('style')
        if stylefile:
            basedir = os.path.dirname(os.path.abspath(self.config.input))
            stylepath = os.path.join(basedir, stylefile)
            if os.path.exists(stylepath):
                # stylename exists on relative path from source file
                self.stylepackage = os.path.splitext(stylepath)[0]
            else:
                warning('stylefile not found: %s' % stylefile)
Example #15
0
def create_formula_image(formula, formula_env, stylepackage):
    try:
        tmpdir = mkdtemp()

        # create source .tex file
        source = NamedTemporaryFile(mode='w+b', suffix='.tex',
                                    dir=tmpdir, delete=False)
        latex_source = get_latex_source(formula, formula_env, stylepackage)
        source.write(latex_source.encode('utf-8'))
        source.close()

        # execute platex
        try:
            # `-no-shell-escape` blocks to invoke any commands
            args = ['platex', '--interaction=nonstopmode',
                    '-no-shell-escape', source.name]
            latex = Popen(args, stdout=PIPE, stderr=PIPE, cwd=tmpdir)
            stdout, _ = latex.communicate()
            if latex.returncode != 0:
                warning("raise LaTeX Exception:\n\n%s" %
                        stdout.decode('utf-8'))
                return None
        except Exception as exc:
            if isinstance(exc, OSError) and exc.errno == ENOENT:
                error = 'platex command not found'
            else:
                error = exc

            warning("Fail to convert formula: %s (reason: %s)" %
                    (formula, error))
            return None

        # execute dvipng
        try:
            dvifile = source.name.replace('.tex', '.dvi')
            output = NamedTemporaryFile(suffix='.png')
            args = ['dvipng', '-gamma', '1.5',
                    '-D', '110', '-T', 'tight',
                    '-bg', 'Transparent', '-z0', dvifile,
                    '-o', output.name]
            dvipng = Popen(args, stdout=PIPE, stderr=PIPE, cwd=tmpdir)
            stdout, _ = dvipng.communicate()
            if latex.returncode != 0:
                warning("raise dvipng Exception:\n\n%s" %
                        stdout.decode('utf-8'))
                return None
        except Exception as exc:
            output.close()
            if isinstance(exc, OSError) and exc.errno == ENOENT:
                error = 'dvipng command not found'
            else:
                error = exc

            warning("Fail to convert formula: %s (reason: %s)" %
                    (formula, error))
            return None

        return output
    finally:
        rmtree(tmpdir)
Example #16
0
def load(plugins, diagram, **kwargs):
    for name in plugins:
        if name in loaded_plugins:
            warning('plugin "%s" is already loaded. ignored.', name)
            return

        for ep in iter_entry_points('blockdiag_plugins', name):
            module = ep.load()
            loaded_plugins.append(name)
            if hasattr(module, 'setup'):
                module.setup(module, diagram, **kwargs)
            break
        else:
            msg = "unknown plugin: %s" % name
            raise AttributeError(msg)
Example #17
0
def wand_open(url, stream):
    try:
        import wand.image
    except:
        warning("unknown image type: %s", url)
        raise IOError

    try:
        png_image = io.BytesIO()
        with wand.image.Image(file=stream) as img:
            img.format = 'PNG'
            img.save(file=png_image)
            png_image.seek(0)
            return png_image
    except Exception as exc:
        warning("Fail to convert %s to PNG: %r", url, exc)
        raise IOError
Example #18
0
    def find(self, element=None):
        fontfamily = getattr(element, "fontfamily", None) or self.default_fontfamily
        fontfamily = self.aliases.get(fontfamily, fontfamily)
        fontsize = getattr(element, "fontsize", None) or self.fontsize

        name = self._regulate_familyname(fontfamily)
        if name in self.fonts:
            font = self.fonts[name].duplicate()
            font.size = fontsize
        elif element is not None:
            warning("Unknown fontfamily: %s", fontfamily)
            elem = namedtuple("Font", "fontsize")(fontsize)
            font = self.find(elem)
        else:
            font = None

        return font
Example #19
0
    def find(self, element=None):
        fontfamily = getattr(element, 'fontfamily', None) or \
            self.default_fontfamily
        fontfamily = self.aliases.get(fontfamily, fontfamily)
        fontsize = getattr(element, 'fontsize', None) or self.fontsize

        name = self._regulate_familyname(fontfamily)
        if name in self.fonts:
            font = self.fonts[name].duplicate()
            font.size = fontsize
        elif element is not None:
            warning("Unknown fontfamily: %s", fontfamily)
            elem = namedtuple('Font', 'fontsize')(fontsize)
            font = self.find(elem)
        else:
            font = None

        return font
Example #20
0
    def on_attr_changing(self, node, attr):
        if attr.name not in ('background', 'icon'):
            return True

        value = unquote(attr.value)
        matched = prefix.match(value)
        if not matched:
            return True

        code = icons.get(matched.group(1))
        if code is None:
            warning('unknown octicon: %s', value)
            setattr(node, attr.name, None)
            return False

        if value not in icon_images:
            options = to_option(matched.group(2))
            image = self.create_octicon_image(code, options)
            icon_images[value] = image

        setattr(node, attr.name, icon_images[value])
        return False
Example #21
0
    def create_formula_image(self, formula):
        try:
            tmpdir = mkdtemp()

            # create source .tex file
            source = NamedTemporaryFile(mode='w+b', suffix='.tex',
                                        dir=tmpdir, delete=False)
            source.write((LATEX_SOURCE % formula).encode('utf-8'))
            source.close()

            # execute platex
            args = ['platex', '--interaction=nonstopmode', source.name]
            latex = Popen(args, stdout=PIPE, stderr=PIPE, cwd=tmpdir)
            stdout, stderr = latex.communicate()
            if latex.returncode != 0:
                warning("Fail to convert formula: %s", formula)
                warning("Reason: %s" % stdout)
                return None

            # execute dvipng
            dvifile = source.name.replace('.tex', '.dvi')
            output = NamedTemporaryFile(suffix='.png')
            args = ['dvipng', '-gamma', '1.5', '-D', '110', '-T', 'tight',
                    '-bg', 'Transparent', '-z0', dvifile, '-o', output.name]
            dvipng = Popen(args, stdout=PIPE, stderr=PIPE, cwd=tmpdir)
            stdout, stderr = dvipng.communicate()
            if latex.returncode != 0:
                warning("Fail to convert formula: %s", formula)
                warning("Reason: %s" % stdout)

                output.close()
                return None

            return output
        finally:
            rmtree(tmpdir)
Example #22
0
 def set_default_line_color(self, color):
     warning("default_line_color is obsoleted; use default_linecolor")
     self.set_default_linecolor(color)
Example #23
0
 def set_default_text_color(self, color):
     warning("default_text_color is obsoleted; use default_textcolor")
     self.set_default_textcolor(color)
Example #24
0
 def set_background(self, value):
     if urlutil.isurl(value) or os.path.isfile(value):
         self.background = value
     else:
         warning("background image not found: %s", value)
Example #25
0
 def set_icon(self, value):
     if urlutil.isurl(value) or os.path.isfile(value):
         self.icon = value
     else:
         warning("icon image not found: %s", value)
Example #26
0
 def set_fontsize(self, value):
     warning("fontsize is obsoleted; use default_fontsize")
     self.set_default_fontsize(int(value))
Example #27
0
 def set_activation(self, value):
     value = value.lower()
     if value == 'none':
         self.activation = value
     else:
         warning("unknown activation style: %s", value)
Example #28
0
 def set_edge_height(self, value):
     warning("edge_height is obsoleted; use span_height")
     self.span_height = int(value)
Example #29
0
 def set_icon(self, value):
     if urlutil.isurl(value) or os.path.isfile(value):
         self.icon = value
     else:
         warning("icon image not found: %s", value)
Example #30
0
 def set_background(self, value):
     if urlutil.isurl(value) or os.path.isfile(value):
         self.background = value
     else:
         warning("background image not found: %s", value)
Example #31
0
 def set_default_text_color(self, color):
     warning("default_text_color is obsoleted; use default_textcolor")
     self.set_default_textcolor(color)
Example #32
0
 def set_edge_height(self, value):
     warning("edge_height is obsoleted; use span_height")
     self.span_height = int(value)
Example #33
0
 def set_fontsize(self, value):
     warning("fontsize is obsoleted; use default_fontsize")
     self.set_default_fontsize(int(value))
Example #34
0
 def set_dir(self, value):
     params = self.ARROW_DEF.get(value.lower())
     if params is None:
         warning("unknown edge dir: %s", value)
     else:
         self.dir, self.style, self.async = params
Example #35
0
 def set_activation(self, value):
     value = value.lower()
     if value == 'none':
         self.activation = value
     else:
         warning("unknown activation style: %s", value)
Example #36
0
 def set_default_line_color(self, color):
     warning("default_line_color is obsoleted; use default_linecolor")
     self.set_default_linecolor(color)
Example #37
0
    def __init__(self, diagram, **kwargs):
        super(DiagramMetrics, self).__init__(diagram, **kwargs)

        self.node_count = len(diagram.nodes)
        self.edges = diagram.edges
        self.separators = diagram.separators
        self.page_padding = [0, 0, self.cellsize * 3, 0]

        if diagram.edge_length:
            span_width = diagram.edge_length - self.node_width
            if span_width < 0:
                warning("edge_length is too short: %d", diagram.edge_length)
                span_width = 0

            self.spreadsheet.set_span_width(0, self.span_width)
            self.spreadsheet.set_span_width(self.node_count, self.span_width)
            self.span_width = span_width

        for edge in diagram.edges:
            edge.textwidth, edge.textheight = self.edge_textsize(edge)

            height = self.edge_height + edge.textheight
            if edge.diagonal:
                height += self.node_height * 3 // 4
            elif edge.direction == 'self':
                height += self.cellsize * 2

            font = self.font_for(edge)
            if edge.leftnote:
                edge.leftnotesize = self.textsize(edge.leftnote, font=font)
                if height < edge.leftnotesize.height:
                    height = edge.leftnotesize.height

            if edge.rightnote:
                edge.rightnotesize = self.textsize(edge.rightnote, font=font)
                if height < edge.rightnotesize.height:
                    height = edge.rightnotesize.height

            self.spreadsheet.set_node_height(edge.order + 1, height)
            self.expand_pagesize_for_note(edge)

        span_width = defaultdict(int)
        span_height = defaultdict(int)
        for block in diagram.altblocks:
            x1, y1 = block.xy
            x2 = x1 + block.colwidth
            y2 = y1 + block.colheight

            for y in range(y1, y2):
                span_width[(x1, y)] += 1
                span_width[(x2, y)] += 1

            for x in range(x1, x2):
                if block.type != 'else':
                    span_height[(x, y1)] += 1
                span_height[(x, y2)] += 1

        for x in range(self.node_count + 1):
            widths = [span_width[xy] for xy in span_width if xy[0] == x]
            if widths:
                width = self.span_width + max(widths) * self.cellsize
                self.spreadsheet.set_span_width(x, width)

        for y in range(0, len(self.edges) + 1):
            blocks = [b for b in diagram.altblocks if b.edges[0].order == y]
            span_height = self.spreadsheet.span_height[y]
            span_height = 0

            if blocks:
                max_ylevel_top = max(b.ylevel_top for b in blocks)
                span_height = (self.spreadsheet.span_height[y + 1] +
                               self.cellsize * 5 // 2 * (max_ylevel_top - 1) +
                               self.cellsize)
                self.spreadsheet.set_span_height(y + 1, span_height)

            blocks = [b for b in diagram.altblocks if b.edges[-1].order == y]
            if blocks:
                max_ylevel_bottom = max(b.ylevel_bottom for b in blocks)
                span_height = (self.spreadsheet.span_height[y + 2] +
                               self.cellsize // 2 * (max_ylevel_bottom - 1))

                self.spreadsheet.set_span_height(y + 2, span_height)
Example #38
0
    def __init__(self, diagram, **kwargs):
        super(DiagramMetrics, self).__init__(diagram, **kwargs)

        self.node_count = len(diagram.nodes)
        self.edges = diagram.edges
        self.separators = diagram.separators
        self.page_padding = [0, 0, self.cellsize * 3, 0]

        if diagram.edge_length:
            span_width = diagram.edge_length - self.node_width
            if span_width < 0:
                warning("edge_length is too short: %d", diagram.edge_length)
                span_width = 0

            self.spreadsheet.set_span_width(0, self.span_width)
            self.spreadsheet.set_span_width(self.node_count, self.span_width)
            self.span_width = span_width

        for edge in diagram.edges:
            edge.textwidth, edge.textheight = self.edge_textsize(edge)

            height = self.edge_height + edge.textheight
            if edge.diagonal:
                height += self.node_height * 3 // 4
            elif edge.direction == 'self':
                height += self.cellsize * 2

            font = self.font_for(edge)
            if edge.leftnote:
                edge.leftnotesize = self.textsize(edge.leftnote, font=font)
                if height < edge.leftnotesize.height:
                    height = edge.leftnotesize.height

            if edge.rightnote:
                edge.rightnotesize = self.textsize(edge.rightnote, font=font)
                if height < edge.rightnotesize.height:
                    height = edge.rightnotesize.height

            self.spreadsheet.set_node_height(edge.order + 1, height)
            self.expand_pagesize_for_note(edge)

        span_width = defaultdict(int)
        span_height = defaultdict(int)
        for block in diagram.altblocks:
            x1, y1 = block.xy
            x2 = x1 + block.colwidth
            y2 = y1 + block.colheight

            for y in range(y1, y2):
                span_width[(x1, y)] += 1
                span_width[(x2, y)] += 1

            for x in range(x1, x2):
                if block.type != 'else':
                    span_height[(x, y1)] += 1
                span_height[(x, y2)] += 1

        for x in range(self.node_count + 1):
            widths = [span_width[xy] for xy in span_width if xy[0] == x]
            if widths:
                width = self.span_width + max(widths) * self.cellsize
                self.spreadsheet.set_span_width(x, width)

        for y in range(0, len(self.edges) + 1):
            blocks = [b for b in diagram.altblocks if b.edges[0].order == y]
            span_height = self.spreadsheet.span_height[y]
            span_height = 0

            if blocks:
                max_ylevel_top = max(b.ylevel_top for b in blocks)
                span_height = (self.spreadsheet.span_height[y + 1] +
                               self.cellsize * 5 // 2 * (max_ylevel_top - 1) +
                               self.cellsize)
                self.spreadsheet.set_span_height(y + 1, span_height)

            blocks = [b for b in diagram.altblocks if b.edges[-1].order == y]
            if blocks:
                max_ylevel_bottom = max(b.ylevel_bottom for b in blocks)
                span_height = (self.spreadsheet.span_height[y + 2] +
                               self.cellsize // 2 * (max_ylevel_bottom - 1))

                self.spreadsheet.set_span_height(y + 2, span_height)