Package rdkit :: Package Chem :: Package Draw :: Module cairoCanvas
[hide private]
[frames] | no frames]

Source Code for Module rdkit.Chem.Draw.cairoCanvas

  1  # $Id: cairoCanvas.py 1766 2011-06-20 03:49:34Z glandrum $ 
  2  # 
  3  #  Copyright (C) 2008 Greg Landrum 
  4  #  Copyright (C) 2009 Uwe Hoffmann 
  5  # 
  6  #   @@ All Rights Reserved @@ 
  7  #  This file is part of the RDKit. 
  8  #  The contents are covered by the terms of the BSD license 
  9  #  which is included in the file license.txt, found at the root 
 10  #  of the RDKit source tree. 
 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   
28 -class Canvas(CanvasBase):
29 - def __init__(self, 30 image=None, # PIL image 31 size=None, 32 ctx=None, 33 imageType=None, # determines file type 34 fileName=None, # if set determines output file name 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
80 - def flush(self):
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 # on linux at least it seems like the PIL images are BGRA, not RGBA: 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 #bw,bh=w*1.8,h*1.4 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
193 - def addCanvasPolygon(self,ps,color=(0,0,0),fill=True,stroke=False,**kwargs):
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