rdkit.Chem.Draw.aggCanvas

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

# Source Code for Module rdkit.Chem.Draw.aggCanvas

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