happybot/logo.py

133 lines
4.5 KiB
Python

#!/usr/bin/env python3
def sanitize(s):
return s.replace('&', '&')\
.replace('>', '>')\
.replace('<', '&lt;')\
.replace("'", '&apos;')\
.replace('"', '&quot;')
class Tag:
def __init__(self, name, attrs={}, **kwattrs):
self.name = name
self.attrs = attrs
self.attrs.update(kwattrs)
self.children = []
def append(self, *tags):
self.children += tags
return self
def __getitem__(self, n):
return self.children[n]
def __setitem__(self, n, tag):
self.children[n] = tag
def __str__(self):
s = '<' + self.name
for name, value in self.attrs.items():
s += ' ' + name
if value is not None:
s += '="' + sanitize(str(value)) + '"'
if len(self.children) > 0:
s += '>'
for child in self.children:
if isinstance(child, str):
s += sanitize(child)
else:
s += str(child)
s += '</' + self.name + '>'
else:
s += ' />'
return s
def __repr__(self):
return str(self)
def attr(self, **kwargs):
self.attrs.update(kwargs)
return self
class Path(Tag):
def __init__(self, **kwargs):
Tag.__init__(self, 'path', attrs=kwargs)
self.paths = []
def __str__(self):
self.attrs['d'] = ' '.join(self.paths)
return Tag.__str__(self)
def move(self, x, y):
self.paths.append('M ' + str(x) + ' ' + str(y))
return self
def line(self, x, y):
self.paths.append('L ' + str(x) + ' ' + str(y))
return self
def x(self, x):
self.paths.append('H ' + str(x))
return self
def y(self, y):
self.paths.append('V ' + str(y))
return self
def curve(self, x1, y1, x2, y2, x, y):
self.paths.append('C ' + str(x1) + ' ' + str(y1) + ', ' + str(x2) + ' ' + str(y2) + ', ' + str(x) + ' ' + str(y))
return self
def arc(self, xrad, yrad, arcrotxaxis, biggeroption, sweepflag, nextx, nexty):
self.paths.append('A ' + str(xrad) + ' ' + str(yrad) + ', ' + str(arcrotxaxis) + ', ' + str(biggeroption) + ', ' + str(sweepflag) + ', ' + str(nextx) + ' ' + str(nexty))
return self
def close(self):
self.paths.append('Z')
return self
print('<?xml version="1.0" encoding="UTF-8" ?>')
def body(cx, cy, w, h, c=0.03):
topleft = (cx - w/2, cy - h/2)
topright = (cx + w/2, cy - h/2)
bottomleft = (cx - w/2, cy + h/2)
bottomright = (cx + w/2, cy + h/2)
return Path().move(*bottomleft)\
.arc(w*c, h/2, 0, 0, 1, *topleft)\
.arc(w/2, h*c, 0, 1, 0, *topright)\
.arc(w*c, h/2, 0, 0, 1, *bottomright)\
.close()
def eye(cx, cy, w, h, lx=0, ly=0, c=0.01):
def outer(cx, cy, w, h, c=0.01):
topleft = (cx - w/2, cy - h/2)
topright = (cx + w/2, cy - h/2)
bottomleft = (cx - w/2, cy + h/2)
bottomright = (cx + w/2, cy + h/2)
return Path().move(*bottomleft)\
.arc(w*c, h/2, 0, 0, 1, *topleft)\
.arc(w/2, h*c, 0, 0, 1, *topright)\
.arc(w*c, h/2, 0, 0, 1, *bottomright)\
.arc(w/2, h*c, 0, 1, 0, *bottomleft)
def inner(cx, cy, w, h, c=0.01):
topleft = (cx - w/2, cy - h/2)
topright = (cx + w/2, cy - h/2)
bottomleft = (cx - w/2, cy + h/2)
bottomright = (cx + w/2, cy + h/2)
return Path().move(*bottomleft)\
.arc(w*c, h/2, 0, 0, 1, *topleft)\
.arc(w/2, h*c, 0, 0, 1, *topright)\
.arc(w*c, h/2, 0, 0, 1, *bottomright)\
.arc(w/2, h*c, 0, 0, 1, *bottomleft)
icx = cx + lx * w/4
icy = cy + ly * h/4
return Tag('g').append(
outer(cx, cy, w, h, c).attr(fill='white'),
inner(icx, icy, w/2.2, h/2.2, c).attr(fill='black')
).attr(stroke='black')
def eyes(cx, cy, rad, w, h):
return [
eye(cx - rad, cy, w, h, 1, -1),
eye(cx + rad, cy, w, h, -1, -1)
]
def mouth(cx, cy, w, h):
left = (cx - w/2, cy)
right = (cx + w/2, cy)
return Path().move(*left).arc(w/2, h, 0, 0, 0, *right).close().attr(fill='white', stroke='black')
svg = Tag('svg', {'xmlns': 'http://www.w3.org/2000/svg', 'version': '1.1'})
svg.append(body(200, 200, 180, 100).attr(fill='white', stroke='black'))
svg.append(*eyes(200, 185, 64, 50, 56))
svg.append(mouth(200, 210, 55, 35))
print(str(svg))