Coverage for src/pyensae/graphhelper/blockdiag_helper.py: 80%
66 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-03 02:16 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-03 02:16 +0200
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Various functions about :epkg:`blockdiag`.
6.. versionadded:: 1.1
7"""
8import os
9import io
10import glob
13def _create_fontmap(fontmap, font):
14 """
15 Inspired from :epkg:`blockdiag` source file (*_bootstrap.py*).
16 """
17 from blockdiag.utils.fontmap import FontMap
18 fontmap = FontMap(fontmap)
19 if fontmap.find().path is None or font:
20 fontpath = _detectfont(font)
21 fontmap.set_default_font(fontpath)
22 return fontmap
25def _build_diagram(module, builder, drawer, tree, type, code,
26 fontmap=None, antialias=True, nodoctype=False,
27 transparency=False, size=None):
28 """
29 Inspired from :epkg:`blockdiag` source file (*_bootstrap.py*).
30 """
31 ScreenNodeBuilder = builder.ScreenNodeBuilder
32 diagram = ScreenNodeBuilder.build(tree, None)
34 DiagramDraw = drawer.DiagramDraw
35 drawer = DiagramDraw(type, diagram, fontmap=fontmap,
36 code=code, antialias=antialias,
37 nodoctype=nodoctype, transparency=transparency)
38 drawer.draw()
40 if size:
41 return drawer.save(size=size)
42 else:
43 return drawer.save()
46def _detectfont(font):
47 fontdirs = [
48 '/usr/share/fonts',
49 '/Library/Fonts',
50 '/System/Library/Fonts',
51 'c:/windows/fonts',
52 '/usr/local/share/font-*',
53 ]
54 fontfiles = [
55 'ipagp.ttf',
56 'ipagp.otf',
57 'VL-PGothic-Regular.ttf',
58 'Hiragino Sans GB W3.otf',
59 'AppleGothic.ttf',
60 'msgothic.ttf',
61 'msgoth04.ttf',
62 'msgothic.ttc',
63 ]
65 fontpath = None
66 if font:
67 from blockdiag.utils.fontmap import parse_fontpath
68 for path in font:
69 _path, _ = parse_fontpath(path)
70 if os.path.isfile(_path):
71 fontpath = path
72 break
73 else:
74 msg = 'fontfile is not found: %s' % font
75 raise RuntimeError(msg)
77 if fontpath is None:
78 globber = (glob.glob(d) for d in fontdirs)
79 for fontdir in sum(globber, []):
80 for root, _, files in os.walk(fontdir):
81 for font_ in fontfiles:
82 if font_ in files:
83 fontpath = os.path.join(root, font_)
84 break
86 return fontpath
89def draw_diagram(graph, module="blockdiag", format="pillow", **options):
90 """
91 Draws a graph based on module :epkg:`blockdiag`.
93 @param graph graph definition,
94 see `syntax <http://blockdiag.com/en/blockdiag/examples.html>`_
95 @param module ``'blockdiag'`` (only available value)
96 @param format can be a filename or a module name (``'pillow'``)
97 @param options additional options for :epkg:`blockdiag`
98 @return graph
100 ::
102 blockdiag {
103 A -> B -> C -> D;
104 A -> E -> F -> G;
105 }
107 See notebook :ref:`drawdiagramrst`.
108 """
109 if module == "blockdiag":
110 import blockdiag # pylint: disable=C0415
111 module = blockdiag
112 import blockdiag.parser # pylint: disable=C0415
113 parser = blockdiag.parser
114 import blockdiag.builder # pylint: disable=C0415
115 builder = blockdiag.builder
116 import blockdiag.drawer # pylint: disable=C0415
117 drawer = blockdiag.drawer
118 else:
119 raise ValueError(
120 "Unexected value for 'blockdiag': '{0}'".format(module))
122 if format in ("pillow", "png"):
123 ftype = "png"
124 elif format == "svg":
125 ftype = "svg"
126 else:
127 raise ValueError("format should in ['pillow', 'svg']")
129 fontmap = _create_fontmap(fontmap=options.get('fontmap', None),
130 font=options.get('font', None))
131 tree = parser.parse_string(graph)
132 res = _build_diagram(module=module, builder=builder, drawer=drawer,
133 tree=tree, code=graph, fontmap=fontmap, type=ftype,
134 antialias=options.get('antialias', True),
135 nodoctype=options.get('nodoctype', False),
136 transparency=options.get('transparency', False),
137 size=options.get('size', None))
138 if format == "pillow":
139 from PIL import Image
140 image = Image.open(io.BytesIO(res))
141 return image
142 else:
143 return res