Programmatically generate SVG (vector) images, animations, and interactive Jupyter widgets
1import base64 2import urllib.parse 3import re 4 5 6STRIP_CHARS = ('\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f\x10\x11' 7 '\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f') 8 9def bytes_as_data_uri(data, strip_chars=STRIP_CHARS, mime='image/svg+xml'): 10 '''Return a data URI with base64 encoding.''' 11 b64 = base64.b64encode(data) 12 return f'data:{mime};base64,{b64.decode(encoding="ascii")}' 13 14def svg_as_data_uri(txt, strip_chars=STRIP_CHARS, mime='image/svg+xml'): 15 '''Return a data URI with base64 encoding, stripping unsafe chars for SVG. 16 ''' 17 search = re.compile('|'.join(strip_chars)) 18 data_safe = search.sub(lambda m: '', txt) 19 return bytes_as_data_uri(data_safe.encode(encoding='utf-8'), mime=mime) 20 21def svg_as_utf8_data_uri(txt, unsafe_chars='"', strip_chars=STRIP_CHARS, 22 mime='image/svg+xml'): 23 '''Returns a data URI without base64 encoding. 24 25 The characters '#&%' are always escaped. '#' and '&' break parsing of 26 the data URI. If '%' is not escaped, plain text like '%50' will be 27 incorrectly decoded to 'P'. The characters in `strip_chars` cause the 28 SVG not to render even if they are escaped. 29 ''' 30 unsafe_chars = (unsafe_chars or '') + '#&%' 31 replacements = { 32 char: urllib.parse.quote(char, safe='') 33 for char in unsafe_chars 34 } 35 replacements.update({ 36 char: '' 37 for char in strip_chars 38 }) 39 search = re.compile('|'.join(map(re.escape, replacements.keys()))) 40 data_safe = search.sub(lambda m: replacements[m.group(0)], txt) 41 return f'data:{mime};utf8,{data_safe}'