rdkit.Chem.Draw.cairoCanvas

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

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

      1  #
      2  #
      3  #  Copyright (C) 2008 Greg Landrum
      4  #  Copyright (C) 2009 Uwe Hoffmann
      5  #
      6  #   @@ All Rights Reserved  @@
      7  #
      8  import cairo
      9  import math
     10  import rdkit.RDConfig
     11  import os
     12  import array
     13
     14  #missing up to now
     15  #faceMap={'sans':os.path.join(
     16  #    rdkit.RDConfig.RDCodeDir,'Chem','Draw','FreeSans.ttf')}
     17
     18 -class Canvas(object):
     19 -  def __init__(self,
     20                 image=None,  # PIL image
     21                 size=None,
     22                 ctx=None,
     23                 imageType=None, # determines file type
     24                 fileName=None,  # if set determines output file name
     25                 ):
     26      """
     27      Canvas can be used in four modes:
     28      1) using the supplied PIL image
     29      2) using the supplied cairo context ctx
     30      3) writing to a file fileName with image type imageType
     31      4) creating a cairo surface and context within the constructor
     32      """
     33      self.image=None
     34      self.imageType=imageType
     35      if image is not None:
     36        imgd = image.tostring()
     37        a = array.array('B',imgd)
     38        stride = cairo.ImageSurface.format_stride_for_width (cairo.FORMAT_ARGB32,
     39                                                             image.size[0])
     40        if stride != image.size[0] * 4:
     41          raise Exception ,"invalid stride"
     42        surface = cairo.ImageSurface.create_for_data (
     43          a, cairo.FORMAT_ARGB32,
     44          image.size[0], image.size[1], stride)
     45        ctx = cairo.Context(surface)
     46        size=image.size[0], image.size[1]
     47        self.image=image
     48      elif size is not None:
     49        ##cairo.HAS_GLITZ_SURFACE
     50        #cairo.HAS_IMAGE_SURFACE
     51        ##cairo.HAS_QUARTZ_SURFACE
     52        ##cairo.HAS_USER_FONT
     53        #cairo.HAS_WIN32_SURFACE
     54        #cairo.HAS_XCB_SURFACE
     55        ##cairo.HAS_XLIB_SURFACE
     56        #cairo.HAS_PNG_FUNCTIONS
     57        #print imageType
     58        if cairo.HAS_PDF_SURFACE and imageType == "pdf":
     59          surface = cairo.PDFSurface (fileName, size[0], size[1])
     60        elif cairo.HAS_SVG_SURFACE and imageType == "svg":
     61          surface = cairo.SVGSurface (fileName, size[0], size[1])
     62        elif cairo.HAS_PS_SURFACE and imageType == "ps":
     63          surface = cairo.PSSurface (fileName, size[0], size[1])
     64        elif cairo.HAS_IMAGE_SURFACE and imageType == "png":
     65          surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, size[0], size[1])
     66        else:
     67          raise Exception, "Wrong file type"
     68        ctx = cairo.Context(surface)
     69        ctx.set_source_rgb(255,255,255)
     70        ctx.paint()
     71      else:
     72        surface=ctx.get_target()
     73        try:
     74          size=surface.get_width(),surface.get_height()
     75        except AttributeError:
     76          size=None
     77      self.ctx=ctx
     78      self.size=size
     79      self.surface=surface
     80      self.fileName=fileName
     81
     82
     83 -  def flush(self):
     84      """temporary interface, must be splitted to different methods,
     85         (elif self.imageType == "png":)"""
     86      try:
     87        if self.fileName:
     88          self.surface.write_to_png(self.fileName)
     89      except AttributeError:
     90        pass
     91      if self.image is not None:
     92        self.image.fromstring(self.surface.get_data(),
     93                              "raw","RGBA",0,1)
     94        self.surface.finish()
     95      elif self.imageType == "png":
     96        buffer=self.surface.get_data()
     97        return buffer
     98
     99
    100 -def convertColor(color):
    101    color = (int(color[0]*255),int(color[1]*255),int(color[2]*255))
    102    return color
    103
    104 -def _getLinePoints(p1,p2,dash):
    105    x1,y1=p1
    106    x2,y2=p2
    107    dx = x2-x1
    108    dy = y2-y1
    109    lineLen = math.sqrt(dx*dx+dy*dy)
    110    theta = math.atan2(dy,dx)
    111    cosT = math.cos(theta)
    112    sinT = math.sin(theta)
    113
    114    pos = (x1,y1)
    115    pts = [pos]
    116    dist = 0
    117    currDash = 0
    118    while dist < lineLen:
    119      currL = dash[currDash%len(dash)]
    120      if(dist+currL > lineLen): currL = lineLen-dist
    121      endP = (pos[0] + currL*cosT, pos[1] + currL*sinT)
    122      pts.append(endP)
    123      pos = endP
    124      dist += currL
    125      currDash += 1
    126    return pts
    127
    128 -def _doLine(canvas,p1,p2,**kwargs):
    129    if kwargs.get('dashes',(0,0)) == (0,0):
    130      canvas.ctx.move_to(p1[0],p1[1])
    131      canvas.ctx.line_to(p2[0],p2[1])
    132    else:
    133      # the antialiasing makes the dashes appear too small
    134      dash = [x*4 for x in kwargs['dashes']]
    135      pts = _getLinePoints(p1,p2,dash)
    136
    137      currDash = 0
    138      dashOn = True
    139      while currDash<(len(pts)-1):
    140        if dashOn:
    141          p1 = pts[currDash]
    142          p2 = pts[currDash+1]
    143          canvas.ctx.move_to(p1[0],p1[1])
    144          canvas.ctx.line_to(p2[0],p2[1])
    145        currDash+=1
    146        dashOn = not dashOn
    147
    148 -def addCanvasLine(canvas,p1,p2,color=(0,0,0),color2=None,**kwargs):
    149    canvas.ctx.set_line_width(kwargs.get('linewidth',1))
    150    if color2 and color2!=color:
    151      mp = (p1[0]+p2[0])/2.,(p1[1]+p2[1])/2.
    152      color = convertColor(color)
    153      canvas.ctx.set_source_rgb(*color)
    154      _doLine(canvas,p1,mp,**kwargs)
    155      canvas.ctx.stroke()
    156      color2 = convertColor(color2)
    157      canvas.ctx.set_source_rgb(*color2)
    158      _doLine(canvas,mp,p2,**kwargs)
    159      canvas.ctx.stroke()
    160    else:
    161      color = convertColor(color)
    162      canvas.ctx.set_source_rgb(*color)
    163      _doLine(canvas,p1,p2,**kwargs)
    164      canvas.ctx.stroke()
    165
    166 -def addCanvasText(canvas,text,pos,font,color=(0,0,0),**kwargs):
    167    color = convertColor(color)
    168    canvas.ctx.select_font_face("Georgia",
    169                                cairo.FONT_SLANT_NORMAL,
    170                                cairo.FONT_WEIGHT_BOLD)
    171    canvas.ctx.set_font_size(font.size)
    172    w,h=canvas.ctx.text_extents(text)[2:4]
    173    bw,bh=w*1.8,h*1.4
    174    dPos = pos[0]-bw/2.,pos[1]-bh/2.
    175    bgColor=kwargs.get('bgColor',(1,1,1))
    176    bgColor = convertColor(bgColor)
    177    canvas.ctx.set_source_rgb(*bgColor)
    178    canvas.ctx.rectangle(dPos[0],dPos[1],bw,bh)
    179    canvas.ctx.fill()
    180    dPos = pos[0]-w/2.,pos[1]+h/2.
    181    canvas.ctx.set_source_rgb(*color)
    182    canvas.ctx.move_to(*dPos)
    183    canvas.ctx.show_text(text)
    184
    185 -def addCanvasPolygon(canvas,ps,color=(0,0,0),**kwargs):
    186    dps = []
    187    color = convertColor(color)
    188    canvas.ctx.set_source_rgb(*color)
    189    canvas.ctx.move_to(ps[0][0],ps[0][1])
    190    for p in ps[1:]:
    191      canvas.ctx.move_to(p[0],p[1])
    192    canvas.ctx.close_path()
    193    canvas.ctx.fill()
    194
    195 -def addCanvasDashedWedge(canvas,p1,p2,p3,dash=(2,2),color=(0,0,0),
    196                           color2=None,**kwargs):
    197    canvas.ctx.set_line_width(kwargs.get('linewidth',1))
    198    color = convertColor(color)
    199    canvas.ctx.set_source_rgb(*color)
    200    dash = (3,3)
    201    pts1 = _getLinePoints(p1,p2,dash)
    202    pts2 = _getLinePoints(p1,p3,dash)
    203
    204    if len(pts2)<len(pts1): pts2,pts1=pts1,pts2
    205
    206    for i in range(len(pts1)):
    207      canvas.ctx.move_to(pts1[i][0],pts1[i][1])
    208      canvas.ctx.line_to(pts2[i][0],pts2[i][1])
    209    canvas.ctx.stroke()
    210