1
2
3
4
5
6
7
8
9
10 import os
11 import re
12
13 from aggdraw import Brush, Pen
14 from aggdraw import Draw
15 from aggdraw import Font
16 from rdkit import RDConfig
17 from rdkit.Chem.Draw.canvasbase import CanvasBase
18
19 faceMap = {'sans': os.path.join(RDConfig.RDCodeDir, 'Chem', 'Draw', 'FreeSans.ttf')}
20
21
23 color = (int(color[0] * 255), int(color[1] * 255), int(color[2] * 255))
24 return color
25
26
28
29
30 fontScale = 1.2
31
32 - def __init__(self,
33 img=None,
34 imageType=None,
35 fileName=None,
36 size=None, ):
37 if img is None:
38 try:
39 import Image
40 except ImportError:
41 from PIL import Image
42 if size is None:
43 raise ValueError('please provide either an image or a size')
44 img = Image.new('RGBA', size, "white")
45 self.image = img
46 self.draw = Draw(img)
47 self.draw.setantialias(True)
48 if size is None:
49 self.size = self.draw.size
50 else:
51 self.size = size
52 if imageType and imageType not in ('png', 'jpg'):
53 raise ValueError('unsupported image type for agg canvas')
54 self.drawType = imageType
55 self.fileName = fileName
56
57 - def _doLine(self, p1, p2, pen, **kwargs):
58 if kwargs.get('dash', (0, 0)) == (0, 0):
59 self.draw.line((p1[0], p1[1], p2[0], p2[1]), pen)
60 else:
61 dash = kwargs['dash']
62 pts = self._getLinePoints(p1, p2, dash)
63
64 currDash = 0
65 dashOn = True
66 while currDash < (len(pts) - 1):
67 if dashOn:
68 p1 = pts[currDash]
69 p2 = pts[currDash + 1]
70 self.draw.line((p1[0], p1[1], p2[0], p2[1]), pen)
71 currDash += 1
72 dashOn = not dashOn
73
74 - def addCanvasLine(self, p1, p2, color=(0, 0, 0), color2=None, **kwargs):
75 if color2 and color2 != color:
76 mp = (p1[0] + p2[0]) / 2., (p1[1] + p2[1]) / 2.
77 color = convertColor(color)
78 self._doLine(p1, mp, Pen(color, kwargs.get('linewidth', 1)), **kwargs)
79 color2 = convertColor(color2)
80 self._doLine(mp, p2, Pen(color2, kwargs.get('linewidth', 1)), **kwargs)
81 else:
82 color = convertColor(color)
83 self._doLine(p1, p2, Pen(color, kwargs.get('linewidth', 1)), **kwargs)
84
85 - def addCanvasText(self, text, pos, font, color=(0, 0, 0), **kwargs):
86 orientation = kwargs.get('orientation', 'E')
87 color = convertColor(color)
88 aggFont = Font(color, faceMap[font.face], size=font.size * self.fontScale)
89
90 blocks = list(re.finditer(r'\<(.+?)\>(.+?)\</\1\>', text))
91 w, h = 0, 0
92 supH = 0
93 subH = 0
94 if not len(blocks):
95 w, h = self.draw.textsize(text, aggFont)
96 tw, th = w, h
97 offset = w * pos[2]
98 dPos = pos[0] - w / 2. + offset, pos[1] - h / 2.
99 self.draw.text(dPos, text, aggFont)
100 else:
101 dblocks = []
102 idx = 0
103 for block in blocks:
104 blockStart, blockEnd = block.span(0)
105 if blockStart != idx:
106
107 tblock = text[idx:blockStart]
108 tw, th = self.draw.textsize(tblock, aggFont)
109 w += tw
110 h = max(h, th)
111 dblocks.append((tblock, '', tw, th))
112 fmt = block.groups()[0]
113 tblock = block.groups()[1]
114 if fmt in ('sub', 'sup'):
115 lFont = Font(color, faceMap[font.face], size=0.8 * font.size * self.fontScale)
116 else:
117 lFont = aggFont
118 tw, th = self.draw.textsize(tblock, lFont)
119 w += tw
120 if fmt == 'sub':
121 subH = max(subH, th)
122 elif fmt == 'sup':
123 supH = max(supH, th)
124 else:
125 h = max(h, th)
126 dblocks.append((tblock, fmt, tw, th))
127 idx = blockEnd
128 if idx != len(text):
129
130 tblock = text[idx:]
131 tw, th = self.draw.textsize(tblock, aggFont)
132 w += tw
133 h = max(h, th)
134 dblocks.append((tblock, '', tw, th))
135
136 supH *= 0.5
137 subH *= 0.5
138 h += supH + subH
139 offset = w * pos[2]
140 dPos = [pos[0] - w / 2. + offset, pos[1] - h / 2.]
141 if orientation == 'W':
142 dPos = [pos[0] - w + offset, pos[1] - h / 2.]
143 elif orientation == 'E':
144 dPos = [pos[0] + offset, pos[1] - h / 2.]
145 else:
146 dPos = [pos[0] - w / 2 + offset, pos[1] - h / 2.]
147
148 if supH:
149 dPos[1] += supH
150 for txt, fmt, tw, th in dblocks:
151 tPos = dPos[:]
152 if fmt == 'sub':
153 tPos[1] += subH
154 elif fmt == 'sup':
155 tPos[1] -= supH
156 if fmt in ('sub', 'sup'):
157 lFont = Font(color, faceMap[font.face], size=0.8 * font.size * self.fontScale)
158 else:
159 lFont = aggFont
160 self.draw.text(tPos, txt, lFont)
161 dPos[0] += tw
162 return (tw + th * .4, th + th * .4, offset)
163
164 - def addCanvasPolygon(self, ps, color=(0, 0, 0), fill=True, stroke=False, **kwargs):
165 if not fill and not stroke:
166 return
167 dps = []
168 for p in ps:
169 dps.extend(p)
170 color = convertColor(color)
171 brush = None
172 pen = None
173 if fill:
174 brush = Brush(color)
175 if stroke:
176 pen = Pen(color)
177 self.draw.polygon(dps, pen, brush)
178
179 - def addCanvasDashedWedge(self, p1, p2, p3, dash=(2, 2), color=(0, 0, 0), color2=None, **kwargs):
180 pen = Pen(color, kwargs.get('linewidth', 1))
181 dash = (3, 3)
182 pts1 = self._getLinePoints(p1, p2, dash)
183 pts2 = self._getLinePoints(p1, p3, dash)
184
185 if len(pts2) < len(pts1):
186 pts2, pts1 = pts1, pts2
187
188 for i in range(len(pts1)):
189 self.draw.line((pts1[i][0], pts1[i][1], pts2[i][0], pts2[i][1]), pen)
190
192 self.draw.flush()
193 if self.fileName:
194 self.image.save(self.fileName)
195