1# -*- coding: utf-8 -*-2# Copyright 2011 Takeshi KOMIYA3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.1516import re17from io import StringIO181920def _escape(s):21 if not isinstance(s, str):22 s = str(s)23 return s.replace("&", "&").replace("<", "<").replace(">", ">")242526def _quote(s):27 return '"%s"' % _escape(s).replace('"', """)282930class base(object):31 def __init__(self, *args, **kwargs):32 self.text = None33 self.elements = []34 self.attributes = {}35 for key, value in kwargs.items():36 self.add_attribute(key, value)3738 def add_attribute(self, key, value):39 setter = 'set_%s' % key40 if hasattr(self, setter):41 getattr(self, setter)(value)42 else:43 key = re.sub('_', '-', key)44 self.attributes[key] = value4546 def addElement(self, element):47 self.elements.append(element)4849 def set_text(self, text):50 self.text = text5152 def to_xml(self, io, level=0):53 clsname = self.__class__.__name__54 indent = ' ' * level5556 io.write('%s<%s' % (indent, clsname))57 for key in sorted(self.attributes):58 value = self.attributes[key]59 if value is not None:60 io.write(' %s=%s' % (_escape(key), _quote(value)))6162 if self.elements == []:63 if self.text is not None:64 io.write(">%s</%s>\n" % (_escape(self.text), clsname))65 else:66 io.write(" />\n")67 elif self.elements:68 if self.text is not None:69 io.write(">%s\n" % (_escape(self.text),))70 else:71 io.write(">\n")7273 for e in self.elements:74 e.to_xml(io, level + 1)75 io.write('%s</%s>\n' % (indent, clsname))767778class element(base):79 def __init__(self, x, y, width=None, height=None, *args, **kwargs):80 super(element, self).__init__(*args, **kwargs)81 self.attributes['x'] = x82 self.attributes['y'] = y83 if width is not None:84 self.attributes['width'] = width85 if height is not None:86 self.attributes['height'] = height878889class svg(base):90 def __init__(self, x, y, width, height, **kwargs):91 if kwargs.get('noviewbox'):92 super(svg, self).__init__(width=(width - x), height=(height - y))93 else:94 viewbox = "%d %d %d %d" % (x, y, width, height)95 super(svg, self).__init__(viewBox=viewbox)9697 self.nodoctype = kwargs.get('nodoctype', False)98 self.add_attribute('xmlns', 'http://www.w3.org/2000/svg')99100 def to_xml(self):101 io = StringIO()102103 if not self.nodoctype:104 url = "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"105 io.write("<?xml version='1.0' encoding='UTF-8'?>\n")106 io.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "%s">\n' % url)107108 super(svg, self).to_xml(io)109110 return io.getvalue()111112113class title(base):114 def __init__(self, _title):115 super(title, self).__init__(text=_title)116117118class desc(base):119 def __init__(self, _title):120 super(desc, self).__init__(text=_title)121122123class text(element):124 def __init__(self, x, y, _text, **kwargs):125 super(text, self).__init__(x, y, text=_text, **kwargs)126127128class rect(element):129 pass130131132class ellipse(base):133 def __init__(self, cx, cy, rx, ry, **kwargs):134 super(ellipse, self).__init__(cx=cx, cy=cy, rx=rx, ry=ry, **kwargs)135136137class image(element):138 def __init__(self, uri, x, y, width, height, **kwargs):139 super(image, self).__init__(x, y, width, height, **kwargs)140 self.add_attribute('xlink:href', uri)141142143class polygon(base):144 def __init__(self, points, **kwargs):145 xylist = " ".join('%d,%d' % pt for pt in points)146 super(polygon, self).__init__(points=xylist, **kwargs)147148149class path(base):150 def __init__(self, data, **kwargs):151 super(path, self).__init__(d=data, **kwargs)152153154class pathdata:155 def __init__(self, x=None, y=None):156 self.path = []157 if x is not None and y is not None:158 self.move(x, y)159160 def closepath(self):161 self.path.append('z')162163 def move(self, x, y):164 self.path.append('M %s %s' % (x, y))165166 def relmove(self, x, y):167 self.path.append('m %s %s' % (x, y))168169 def line(self, x, y):170 self.path.append('L %s %s' % (x, y))171172 def relline(self, x, y):173 self.path.append('l %s %s' % (x, y))174175 def hline(self, x):176 self.path.append('H%s' % (x,))177178 def relhline(self, x):179 self.path.append('h%s' % (x,))180181 def vline(self, y):182 self.path.append('V%s' % (y,))183184 def relvline(self, y):185 self.path.append('v%s' % (y,))186187 def bezier(self, x1, y1, x2, y2, x, y):188 self.path.append('C%s,%s %s,%s %s,%s' % (x1, y1, x2, y2, x, y))189190 def relbezier(self, x1, y1, x2, y2, x, y):191 self.path.append('c%s,%s %s,%s %s,%s' % (x1, y1, x2, y2, x, y))192193 def smbezier(self, x2, y2, x, y):194 self.path.append('S%s,%s %s,%s' % (x2, y2, x, y))195196 def relsmbezier(self, x2, y2, x, y):197 self.path.append('s%s,%s %s,%s' % (x2, y2, x, y))198199 def qbezier(self, x1, y1, x, y):200 self.path.append('Q%s,%s %s,%s' % (x1, y1, x, y))201202 def qrelbezier(self, x1, y1, x, y):203 self.path.append('q%s,%s %s,%s' % (x1, y1, x, y))204205 def smqbezier(self, x, y):206 self.path.append('T%s %s' % (x, y))207208 def relsmqbezier(self, x, y):209 self.path.append('t%s %s' % (x, y))210211 def ellarc(self, rx, ry, xrot, laf, sf, x, y):212 self.path.append('A%s,%s %s %s %s %s %s' %213 (rx, ry, xrot, laf, sf, x, y))214215 def relellarc(self, rx, ry, xrot, laf, sf, x, y):216 self.path.append('a%s,%s %s %s %s %s %s' %217 (rx, ry, xrot, laf, sf, x, y))218219 def __repr__(self):220 return ' '.join(self.path)221222223class defs(base):224 pass225226227class g(base):228 pass229230231class a(base):232 pass233234235class filter(element):236 def __init__(self, x, y, width, height, **kwargs):237 super(filter, self).__init__(x, y, width, height, **kwargs)238239240def svgclass(name):241 """ svg class generating function """242 return type(name, (base,), {})