···449449Note: The above example currently only works in `jupyter notebook`, not `jupyter lab`.
450450451451452452+### Embed custom fonts
453453+```python
454454+import drawsvg as draw
455455+456456+d = draw.Drawing(400, 100, origin='center')
457457+d.embed_google_font('Permanent Marker', text=set('Text with custom font'))
458458+459459+d.append(draw.Text('Text with custom font', 35, 0, 0, center=True,
460460+ font_family='Permanent Marker', font_style='italic'))
461461+462462+d.save_svg('font.svg')
463463+d # Custom fonts work in most browsers but not in rasterize(), save_png(), or save_video()
464464+```
465465+466466+[](https://github.com/cduck/drawsvg/blob/master/examples/font.svg)
467467+468468+452469---
453470454471# Full-feature install
+15-1
drawsvg/drawing.py
···66import xml.sax.saxutils as xml
7788from . import (
99- types, elements as elements_module, raster, video, jupyter, native_animation
99+ types, elements as elements_module, raster, video, jupyter,
1010+ native_animation, font_embed,
1011)
11121213···160161 self.append(elements_module.Title(text, **kwargs))
161162 def append_css(self, css_text):
162163 self.css_list.append(css_text)
164164+ def embed_google_font(self, family, text=None, display='swap', **kwargs):
165165+ '''Download SVG-embeddable CSS from Google fonts.
166166+167167+ Args:
168168+ family: Name of font family or list of font families.
169169+ text: The set of characters required from the font. Only a font
170170+ subset with these characters will be downloaded.
171171+ display: The font-display CSS value.
172172+ **kwargs: Other URL parameters sent to
173173+ https://fonts.googleapis.com/css?...
174174+ '''
175175+ self.append_css(font_embed.download_google_font_css(
176176+ family, text=text, display=display, **kwargs))
163177 def append_javascript(self, js_text, onload=None):
164178 if onload:
165179 if self.svg_args.get('onload'):
+48
drawsvg/font_embed.py
···11+import urllib.request, urllib.parse
22+import re
33+44+from . import url_encode
55+66+77+def download_url(url):
88+ with urllib.request.urlopen(url) as r:
99+ return r.read()
1010+1111+def download_url_to_data_uri(url, mime='application/octet-stream'):
1212+ data = download_url(url)
1313+ return url_encode.bytes_as_data_uri(data, strip_chars='', mime=mime)
1414+1515+def embed_css_resources(css):
1616+ '''Replace all URLs in the CSS string with downloaded data URIs.'''
1717+ regex = re.compile(r'url\((https?://[^)]*)\)')
1818+ def repl(match):
1919+ url = match[1]
2020+ uri = download_url_to_data_uri(url)
2121+ return f'url({uri})'
2222+ embedded, _ = regex.subn(repl, css)
2323+ return embedded
2424+2525+def download_google_font_css(family, text=None, display='swap', **kwargs):
2626+ '''Download SVG-embeddable CSS from Google fonts.
2727+2828+ Args:
2929+ family: Name of font family or list of font families.
3030+ text: The set of characters required from the font. Only a font subset
3131+ with these characters will be downloaded.
3232+ display: The font-display CSS value.
3333+ **kwargs: Other URL parameters sent to
3434+ https://fonts.googleapis.com/css?...
3535+ '''
3636+ if not isinstance(family, str):
3737+ family = '|'.join(family) # Request a list of families
3838+ args = dict(family=family, display=display)
3939+ if text is not None:
4040+ if not isinstance(text, str):
4141+ text = ''.join(text)
4242+ args['text'] = text
4343+ args.update(kwargs)
4444+ params = urllib.parse.urlencode(args)
4545+ url = f'https://fonts.googleapis.com/css?{params}'
4646+ with urllib.request.urlopen(url) as r:
4747+ css = r.read().decode('utf-8')
4848+ return embed_css_resources(css)