Package pySVG :: Module pysvg
[hide private]
[frames] | no frames]

Source Code for Module pySVG.pysvg

  1  #!/usr/bin/python 
  2  # -*- coding: iso-8859-1 -*- 
  3  """ 
  4  License: 
  5  Copyright (c) 2008 Kerim Mansour 
  6  All rights reserved. 
  7   
  8  COMMERCIAL USAGE: 
  9  Commercial usage is understood as usage in order to make a profit or in a corporate environment. 
 10  For commercial usage please contact kmansour ATT web DOT de 
 11   
 12  NONCOMMERCIAL USAGE: 
 13  The following license applies to NONCOMMERCIAL usage of the software.  
 14  Redistribution and use in source and binary forms, with or without modification, 
 15  are permitted provided that the following conditions are met: 
 16   
 17      * Redistributions of source code must retain the above copyright notice, 
 18        this list of conditions and the following disclaimer. 
 19      * Redistributions in binary form must reproduce the above copyright notice, 
 20        this list of conditions and the following disclaimer in the documentation  
 21        and/or other materials provided with the distribution. 
 22      * Neither the name of the author nor the names of other contributors  
 23        may be used to endorse or promote products derived from this software without  
 24        specific prior written permission. 
 25   
 26  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
 27  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES  
 28  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE  
 29  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
 30  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  
 31  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
 32  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  
 33  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 34  """ 
 35   
 36  """ 
 37  Not supported as of yet / NOT Working 
 38  Viewport, transforms, gradients.... 
 39  """ 
 40   
 41  SVG_HEADER='''<?xml version="1.0" encoding="UTF-8"?> 
 42  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ''' 
 43  SVG_FOOTER='</svg>' 
 44  END_TAG_LINE='>\n' 
 45   
46 -class SVG:
47 """ Base class for a SVG document """
48 - def __init__(self,title="svg",description="", height=None,width=None, viewBox=None):
49 self.title = title 50 self.descr = description 51 self.height = height 52 self.width = width 53 self.viewBox=viewBox 54 self.elements = []
55
56 - def getXML(self):
57 """ 58 Return a XML representation of the current SVG document. 59 This function can be used for debugging purposes. 60 61 @return: the representation of the current SVG as an xml string 62 """ 63 xml=SVG_HEADER 64 #print height, width etc on demand better that this 65 if self.height!= None: 66 xml+='height="%s" ' % (self.height) 67 68 if self.width!= None: 69 xml+='width="%s" ' % (self.width) 70 71 if self.viewBox!= None: 72 xml+='viewBox="%s" ' % (self.viewBox) 73 74 xml+=END_TAG_LINE 75 for element in self.elements: 76 xml+=element.getXML() 77 xml+=SVG_FOOTER 78 return xml
79
80 - def saveSVG(self, filename):
81 """ 82 Saves the current SVG document into a file. 83 @type filename: string 84 @param filename: file to store the svg in (complete path+filename+extension) 85 """ 86 f=open(filename,'w') 87 xml=self.getXML() 88 f.write(xml) 89 f.close()
90
91 - def addElement(self,element):
92 """ 93 Generic method to add any element to the document 94 @type element: Object that contains a getXML method (circle, line, text, polyline, etc....) 95 @param element: the element to add to the doc 96 """ 97 self.elements.append(element)
98
99 -class BaseElement:
100 """ 101 This is the base class for all svg elements like elipses, texts, lines etc. 102 """
103 - def __init__(self, startTag, style_dict=None, focusable=None,endTag="/>\n"):
104 """ 105 initializes the object 106 @type startTag: string 107 @param startTag: the tag for the svg element name (e.g. <text ) 108 @type style_dict: dictionary 109 @param style_dict: the style to use for this element 110 @type focusable: ?? 111 @param focusable: ?? 112 """ 113 self.startXML=startTag 114 self.endXML=endTag 115 #self.style=style #deprecated 116 self.focusable=focusable 117 self.style_dict=style_dict
118
119 - def getXMLFromStyle(self):
120 """ 121 This method converts the information in the style 122 dictionary into svg syntax for the style attribute 123 124 @return: the representation of the current style as an xml string 125 """ 126 count=0; 127 xml="style=" 128 for key in self.style_dict.keys(): 129 if self.style_dict.get(key)=="": 130 continue 131 if count>0: 132 xml+='; ' 133 else: 134 xml+='"' 135 xml+='%s:%s' %(key,self.style_dict.get(key)) 136 count+=1 137 xml+='" ' 138 if len(xml)>8: 139 return xml 140 else: #empty style 141 return ""
142
143 - def getXML(self):
144 """ 145 Return a XML representation of the current element. 146 This function can be used for debugging purposes. It is also used by getXML in SVG 147 148 @return: the representation of the current element as an xml string 149 """ 150 xml=self.startXML 151 for item in dir(self): 152 if item.find('_')==-1 and item.find('XML')==-1:# and item.find('getXML')==-1: 153 if getattr(self,item) != None: 154 xml+=item+"=\"%s\" " %(getattr(self,item)) 155 elif item=='style_dict': 156 if getattr(self,item) != None: 157 xml+=self.getXMLFromStyle() 158 xml+=self.endXML 159 return xml
160 161
162 -class Group():
163 """ Base class for a container element. Different shapes, paths and 164 text can be put together inside a container sharing the same style. 165 """ 166 startXML="<g " 167 endTag=">\n" 168 endXML="</g>\n" 169
170 - def __init__(self,style_dict=None, transform_dict=None):
171 """ 172 Initialization. 173 @type style_dict: dict 174 @param style_dict: The style that should be applied to all elements within this container 175 """ 176 self.style_dict=style_dict 177 self.transform_dict=transform_dict 178 self.elements=[]
179 180
181 - def addElement(self,element):
182 """ 183 Generic method to add any element to the container 184 @type element: Object that contains a getXML method (circle, line, text, polyline, etc....) 185 @param element: the element to add to the container 186 """ 187 self.elements.append(element)
188
189 - def getXMLFromStyle(self):
190 """ 191 This method converts the information in the style 192 dictionary into svg syntax for the style attribute 193 194 @return: the representation of the current style as an xml string 195 """ 196 if self.style_dict==None: 197 return"" 198 count=0; 199 xml="style=" 200 for key in self.style_dict.keys(): 201 if self.style_dict.get(key)=="": 202 continue 203 if count>0: 204 xml+='; ' 205 else: 206 xml+='"' 207 xml+='%s:%s' %(key,self.style_dict.get(key)) 208 count+=1 209 xml+='" ' 210 if len(xml)>8: 211 return xml 212 else: #empty style 213 return ""
214 215 #todo: format is not nice
216 - def getXMLFromTransform(self):
217 """ 218 This method converts the information in the transform 219 dictionary into svg syntax for the transform attribute 220 221 @return: the representation of the current transformations as an xml string 222 """ 223 if self.transform_dict.keys()==None: 224 return"" 225 count=0; 226 xml="transform=" 227 for key in self.transform_dict.keys(): 228 if self.transform_dict.get(key)=="": 229 continue 230 if count>0: 231 xml+='; ' 232 else: 233 xml+='"' 234 xml+='%s' %(self.transform_dict.get(key)) 235 count+=1 236 xml+='" ' 237 if len(xml)>8: 238 return xml 239 else: #empty style 240 return ""
241
242 - def getXML(self):
243 """ 244 Return a XML representation of the current element. 245 This function can be used for debugging purposes. It is also used by getXML in SVG 246 247 @return: the representation of the current element as an xml string 248 """ 249 xml=self.startXML 250 xml+=self.getXMLFromStyle() 251 xml+=self.getXMLFromTransform() 252 xml+=self.endTag 253 for element in self.elements: 254 xml+=element.getXML() 255 xml+=self.endXML 256 return xml
257 #------------new
258 -class Defs:
259 """ 260 This class packs all definitions 261 """ 262 startXML="<defs>\n" 263 endXML="</defs>\n" 264
265 - def __init__(self):
266 self.definitions=[]
267
268 - def addDefinition(self,definition):
269 self.definitions.append(definition)
270
271 - def removeDefinition(self,id):
272 for defintion in self.definitions: 273 if definition.find('id="'+id+'"')>-1: 274 self.definitions.remove(definition)
275
276 - def getXML(self):
277 """ 278 Return a XML representation of the current element. 279 This function can be used for debugging purposes. It is also used by getXML in SVG 280 281 @return: the representation of the current element as an xml string 282 """ 283 xml=self.startXML 284 xml+=self.getXMLFromStyle() 285 xml+=self.getXMLFromTransform() 286 287 for element in self.elements: 288 xml+=element.getXML() 289 xml+=self.endXML 290 return xml
291
292 -class LinearGradient:
293 startXML="<linearGradient " 294 endTag=">\n" 295 endXML="</linearGradient>\n" 296
297 - def __init__(self, id):
298 self.id=id 299 self.stop=[]
300
301 - def addStop(self,offset,color):
302 s=stop(offset,color) 303 self.stop.apend(s)
304
305 - def getXML(self):
306 """ 307 Return a XML representation of the current element. 308 This function can be used for debugging purposes. It is also used by getXML in SVG 309 310 @return: the representation of the current element as an xml string 311 """ 312 xml=self.startXML 313 for item in dir(self): 314 if item.find('_')==-1 and item.find('XML')==-1:# and item.find('getXML')==-1: 315 if getattr(self,item) != None: 316 xml+=item+"=\"%s\" " %(getattr(self,item)) 317 elif item=='style_dict': 318 if getattr(self,item) != None: 319 xml+=self.getXMLFromStyle() 320 xml+=self.endXML 321 return xml
322
323 -class stop(BaseElement):
324 - def __init__(self,offset,stopcolor):
325 """ 326 Creates a line 327 @type x1: string or int 328 @param x1: starting x-coordinate 329 @type x1: string or int 330 @param y1: starting y-coordinate 331 @type y2: string or int 332 @param x2: ending x-coordinate 333 @type y2: string or int 334 @param y2: ending y-coordinate 335 @type style_dict: dictionary 336 @param style_dict: style(s) to use for this element 337 @type focusable: ??? 338 @param focusable: ?? 339 """ 340 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", None,None) 341 if offset.find('.')>-1: 342 offset=offset[offset.find('.')+1:]+'%' 343 self.offset = offset 344 self.stopcolor = stopcolor
345
346 -def getXML(self):
347 """ 348 Return a XML representation of the current element. 349 This function can be used for debugging purposes. It is also used by getXML in SVG 350 351 @return: the representation of the current element as an xml string 352 """ 353 xml=self.startXML 354 for item in dir(self): 355 if item.find('_')==-1 and item.find('XML')==-1:# and item.find('getXML')==-1: 356 if getattr(self,item) != None: 357 xml+=item+"=\"%s\" " %(getattr(self,item)) 358 xml+=self.endXML 359 return xml
360 361
362 -class line(BaseElement):
363 """ 364 Class representing the line element of an svg doc. 365 Note that this element is NOT painted VISIBLY by default UNLESS you provide 366 a style including STROKE and STROKE-WIDTH 367 """
368 - def __init__(self,x1=None,y1=None,x2=None,y2=None,style_dict=None,focusable=None):
369 """ 370 Creates a line 371 @type x1: string or int 372 @param x1: starting x-coordinate 373 @type x1: string or int 374 @param y1: starting y-coordinate 375 @type y2: string or int 376 @param x2: ending x-coordinate 377 @type y2: string or int 378 @param y2: ending y-coordinate 379 @type style_dict: dictionary 380 @param style_dict: style(s) to use for this element 381 @type focusable: ??? 382 @param focusable: ?? 383 """ 384 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict,focusable) 385 self.x1 = x1 386 self.y1 = y1 387 self.x2=x2 388 self.y2=y2
389 390
391 -class ellipse(BaseElement):
392 """ 393 Class representing the ellipse element of an svg doc. 394 """
395 - def __init__(self,cx=None,cy=None,rx=None,ry=None,style_dict=None,focusable=None):
396 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable) 397 self.cx = cx 398 self.cy = cy 399 self.rx=rx 400 self.ry=ry
401 402
403 -class rect(BaseElement):
404 """ 405 Class representing the rect element of an svg doc. 406 """
407 - def __init__(self,x=None,y=None,width=None,height=None, rx=None, ry=None,style_dict=None,focusable=None):
408 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable) 409 self.x = x 410 self.y = y 411 self.height = height 412 self.width = width 413 self.rx=rx 414 self.ry=ry
415 416
417 -class circle(BaseElement):
418 """ 419 Class representing the cirle element of an svg doc. 420 """
421 - def __init__(self,cx=None,cy=None,r=None,style_dict=None,focusable=None):
422 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable) 423 self.cx = cx 424 self.cy = cy 425 self.r=r
426 427
428 -class polyline(BaseElement):
429 """ 430 Class representing the polyline element of an svg doc. 431 """
432 - def __init__(self,points=None,style_dict=None,focusable=None):
433 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable) 434 self.points = points
435 436 #todo: BaseElement wont work here ... make this class seperate of the hirarchie or try 437 #to make it work ?
438 -class polygon(BaseElement):
439 - def __init__(self,points=None,style_dict=None,focusable=None):
440 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable) 441 self.points = points
442 443
444 -class text(BaseElement):
445 """ 446 Class representing the text element of an svg doc. 447 @type content: string 448 @param content: the text to display 449 @type x: int 450 @param x: x-coordinate for the text 451 @type y: int 452 @param y: y-coordinate for the text 453 @type rotate: int 454 @param rotate: rotation in degrees (negative means counterclockwise) 455 """
456 - def __init__(self,content, x ,y, rotate=None,style_dict=None,editable=None, focusable=None):
457 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable,endTag="</text>\n") 458 self.x=x 459 self.y=y 460 self.rotate=rotate 461 self.editable=editable 462 self.content=content
463
464 - def getXML(self):
465 """ 466 Return a XML representation of the current element. 467 This function can be used for debugging purposes. It is also used by getXML in SVG 468 469 @return: the representation of the current element as an xml string 470 """ 471 xml=self.startXML 472 for item in dir(self): 473 if item.find('_')==-1 and item.find('XML') ==-1 and item.find('content')==-1: 474 if getattr(self,item) != None: 475 xml+=item+"=\"%s\" " %(getattr(self,item)) 476 elif item=='style_dict': 477 if getattr(self,item) != None: 478 xml+=self.getXMLFromStyle() 479 xml+=">" 480 xml+=self.content 481 xml+=self.endXML 482 return xml
483
484 -class path(BaseElement):
485 - def __init__(self,pathData="",pathLength=None,style_dict=None, focusable=None):
486 BaseElement.__init__(self,"<"+self.__class__.__name__+" ", style_dict, focusable) 487 if pathData!='' and not pathData.endswith(' '): 488 pathData+=' ' 489 self.d=pathData
490 #self.pathLength=pathLength 491
492 - def __append__(self,command, params, relative=True):
493 if relative==True: 494 self.d+=command.lower() 495 else: 496 self.d+=command.upper() 497 for param in params: 498 self.d+=' %s ' %(param)
499
500 - def appendLineToPath(self,endx,endy, relative=True):
501 self.__append__('l',[endx,endy], relative)
502
503 - def appendHorizontalLineToPath(self,endx, relative=True):
504 self.__append__('h',[endx], relative)
505
506 - def appendVerticalLineToPath(self,endy, relative=True):
507 self.__append__('v',[endy], relative)
508
509 - def appendMoveToPath(self,endx,endy, relative=True):
510 self.__append__('m',[endx,endy], relative)
511
512 - def appendCloseCurve(self):
513 self.d+="z"
514
515 - def appendCubicCurveToPath(self, controlstartx, controlstarty, controlendx, controlendy, endx,endy,relative=True):
516 self.__append__('c',[controlstartx, controlstarty, controlendx, controlendy, endx,endy], relative)
517
518 - def appendCubicShorthandCurveToPath(self, controlendx, controlendy, endx,endy,relative=True):
519 self.__append__('s',[controlendx, controlendy, endx,endy], relative)
520
521 - def appendQuadraticCurveToPath(self, controlx, controly, endx,endy,relative=True):
522 self.__append__('q',[controlx, controly, endx,endy], relative)
523
524 - def appendQuadraticShorthandCurveToPath(self, endx,endy,relative=True):
525 self.__append__('t',[endx,endy], relative)
526
527 - def appendArcToPath(self,rx,ry,x,y,x_axis_rotation=0,large_arc_flag=0,sweep_flag=1 ,relative=True):
528 self.__append__('a',[rx,ry,x,y,x_axis_rotation,large_arc_flag,sweep_flag], relative)
529
530 - def getXML(self):
531 """ 532 Return a XML representation of the current element. 533 This function can be used for debugging purposes. It is also used by getXML in SVG 534 535 @return: the representation of the current element as an xml string 536 """ 537 xml=self.startXML 538 xml+='d=\"'+self.d+'" ' 539 for item in dir(self): 540 if item.find('_')==-1 and item.find('XML') ==-1 and item.find('append')==-1 and item.find('d')!=0: 541 if getattr(self,item) != None: 542 xml+=item+"=\"%s\" " %(getattr(self,item)) 543 elif item=='style_dict': 544 if getattr(self,item) != None: 545 xml+=self.getXMLFromStyle() 546 547 #xml+='d=\"'+self.d+'"' 548 xml+=self.endXML 549 return xml
550