1
2
3
4
5
6
7
8
9
10
11
12 import cairo
13 import math
14 import rdkit.RDConfig
15 import os,re
16 import array
17 try:
18 import pangocairo
19 except ImportError:
20 pangocairo=None
21 try:
22 import pango
23 except ImportError:
24 pango=None
25
26 from canvasbase import CanvasBase
27
29 - def __init__(self,
30 image=None,
31 size=None,
32 ctx=None,
33 imageType=None,
34 fileName=None,
35 ):
36 """
37 Canvas can be used in four modes:
38 1) using the supplied PIL image
39 2) using the supplied cairo context ctx
40 3) writing to a file fileName with image type imageType
41 4) creating a cairo surface and context within the constructor
42 """
43 self.image=None
44 self.imageType=imageType
45 if image is not None:
46 imgd = image.tostring("raw","BGRA")
47 a = array.array('B',imgd)
48 stride=image.size[0]*4
49 surface = cairo.ImageSurface.create_for_data (
50 a, cairo.FORMAT_ARGB32,
51 image.size[0], image.size[1], stride)
52 ctx = cairo.Context(surface)
53 size=image.size[0], image.size[1]
54 self.image=image
55 elif size is not None:
56 if cairo.HAS_PDF_SURFACE and imageType == "pdf":
57 surface = cairo.PDFSurface (fileName, size[0], size[1])
58 elif cairo.HAS_SVG_SURFACE and imageType == "svg":
59 surface = cairo.SVGSurface (fileName, size[0], size[1])
60 elif cairo.HAS_PS_SURFACE and imageType == "ps":
61 surface = cairo.PSSurface (fileName, size[0], size[1])
62 elif imageType == "png":
63 surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, size[0], size[1])
64 else:
65 raise ValueError, "Unrecognized file type. Valid choices are pdf, svg, ps, and png"
66 ctx = cairo.Context(surface)
67 ctx.set_source_rgb(1,1,1)
68 ctx.paint()
69 else:
70 surface=ctx.get_target()
71 try:
72 size=surface.get_width(),surface.get_height()
73 except AttributeError:
74 size=None
75 self.ctx=ctx
76 self.size=size
77 self.surface=surface
78 self.fileName=fileName
79
81 """temporary interface, must be splitted to different methods,
82 """
83 if self.fileName and self.imageType=='png':
84 self.surface.write_to_png(self.fileName)
85 elif self.image is not None:
86
87 self.image.fromstring(self.surface.get_data(),
88 "raw","BGRA",0,1)
89 self.surface.finish()
90 elif self.imageType == "png":
91 buffer=self.surface.get_data()
92 return buffer
93
94 - def _doLine(self, p1, p2, **kwargs):
95 if kwargs.get('dash',(0,0)) == (0,0):
96 self.ctx.move_to(p1[0],p1[1])
97 self.ctx.line_to(p2[0],p2[1])
98 else:
99 dash = kwargs['dash']
100 pts = self._getLinePoints(p1,p2,dash)
101
102 currDash = 0
103 dashOn = True
104 while currDash<(len(pts)-1):
105 if dashOn:
106 p1 = pts[currDash]
107 p2 = pts[currDash+1]
108 self.ctx.move_to(p1[0],p1[1])
109 self.ctx.line_to(p2[0],p2[1])
110 currDash+=1
111 dashOn = not dashOn
112
113 - def addCanvasLine(self,p1,p2,color=(0,0,0),color2=None,**kwargs):
114 self.ctx.set_line_width(kwargs.get('linewidth',1))
115 if color2 and color2!=color:
116 mp = (p1[0]+p2[0])/2.,(p1[1]+p2[1])/2.
117 self.ctx.set_source_rgb(*color)
118 self._doLine(p1,mp,**kwargs)
119 self.ctx.stroke()
120 self.ctx.set_source_rgb(*color2)
121 self._doLine(mp,p2,**kwargs)
122 self.ctx.stroke()
123 else:
124 self.ctx.set_source_rgb(*color)
125 self._doLine(p1,p2,**kwargs)
126 self.ctx.stroke()
127
128 - def _addCanvasText1(self,text,pos,font,color=(0,0,0),**kwargs):
129 if font.weight=='bold':
130 weight=cairo.FONT_WEIGHT_BOLD
131 else:
132 weight=cairo.FONT_WEIGHT_NORMAL
133 self.ctx.select_font_face(font.face,
134 cairo.FONT_SLANT_NORMAL,
135 weight)
136 text = re.sub(r'\<.+?\>','',text)
137 self.ctx.set_font_size(font.size)
138 w,h=self.ctx.text_extents(text)[2:4]
139 bw,bh=w*1.8,h*1.4
140 dPos = pos[0]-bw/2.,pos[1]-bh/2.
141 bgColor=kwargs.get('bgColor',(1,1,1))
142 self.ctx.set_source_rgb(*bgColor)
143 self.ctx.rectangle(dPos[0],dPos[1],bw,bh)
144 self.ctx.fill()
145 dPos = pos[0]-w/2.,pos[1]+h/2.
146 self.ctx.set_source_rgb(*color)
147 self.ctx.move_to(*dPos)
148 self.ctx.show_text(text)
149 - def _addCanvasText2(self,text,pos,font,color=(0,0,0),**kwargs):
150 if font.weight=='bold':
151 weight=cairo.FONT_WEIGHT_BOLD
152 else:
153 weight=cairo.FONT_WEIGHT_NORMAL
154 self.ctx.select_font_face(font.face,
155 cairo.FONT_SLANT_NORMAL,
156 weight)
157 orientation=kwargs.get('orientation','E')
158 cctx=pangocairo.CairoContext(self.ctx)
159 lout = cctx.create_layout()
160 lout.set_alignment(pango.ALIGN_LEFT)
161 lout.set_markup(text)
162
163 fnt = pango.FontDescription('%s %d'%(font.face,font.size))
164 lout.set_font_description(fnt)
165
166 iext,lext=lout.get_pixel_extents()
167 w=lext[2]-lext[0]
168 h=lext[3]-lext[1]
169
170 if orientation=='W':
171 dPos = pos[0]-w,pos[1]-h/2.
172 elif orientation=='E':
173 dPos = pos[0],pos[1]-h/2.
174 else:
175 dPos = pos[0]-w/2,pos[1]-h/2.
176 bgColor=kwargs.get('bgColor',(1,1,1))
177 self.ctx.set_source_rgb(*bgColor)
178 self.ctx.rectangle(dPos[0],dPos[1],w,h)
179 self.ctx.fill()
180 self.ctx.move_to(dPos[0],dPos[1])
181
182 self.ctx.set_source_rgb(*color)
183 cctx.update_layout(lout)
184 cctx.show_layout(lout)
185
186
187 - def addCanvasText(self,text,pos,font,color=(0,0,0),**kwargs):
188 if pango is not None and pangocairo is not None:
189 self._addCanvasText2(text,pos,font,color,**kwargs)
190 else:
191 self._addCanvasText1(text,pos,font,color,**kwargs)
192
194 if not fill and not stroke: return
195 dps = []
196 self.ctx.set_source_rgb(*color)
197 self.ctx.move_to(ps[0][0],ps[0][1])
198 for p in ps[1:]:
199 self.ctx.line_to(p[0],p[1])
200 self.ctx.close_path()
201 if stroke:
202 if fill:
203 self.ctx.stroke_preserve()
204 else:
205 self.ctx.stroke()
206 if fill:
207 self.ctx.fill()
208
209 - def addCanvasDashedWedge(self,p1,p2,p3,dash=(2,2),color=(0,0,0),
210 color2=None,**kwargs):
211 self.ctx.set_line_width(kwargs.get('linewidth',1))
212 self.ctx.set_source_rgb(*color)
213 dash = (3,3)
214 pts1 = self._getLinePoints(p1,p2,dash)
215 pts2 = self._getLinePoints(p1,p3,dash)
216
217 if len(pts2)<len(pts1): pts2,pts1=pts1,pts2
218
219 for i in range(len(pts1)):
220 self.ctx.move_to(pts1[i][0],pts1[i][1])
221 self.ctx.line_to(pts2[i][0],pts2[i][1])
222 self.ctx.stroke()
223