Skip to content

Instantly share code, notes, and snippets.

@stwind
Last active January 21, 2023 23:14
Show Gist options
  • Save stwind/a6dc61cc7fcb1bf8606ef1c009a00b20 to your computer and use it in GitHub Desktop.
Save stwind/a6dc61cc7fcb1bf8606ef1c009a00b20 to your computer and use it in GitHub Desktop.
Generating Slug font, see https://observablehq.com/@stwind/slug-vector-fonts-rendering for WebGL2 rendering.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Infos:\n",
"numpy: 1.20.0\n",
"seaborn: 0.11.1\n",
"matplotlib: 3.4.1\n"
]
}
],
"source": [
"%matplotlib inline\n",
"%config InlineBackend.figure_format = 'retina'\n",
"\n",
"import io\n",
"import os\n",
"import re\n",
"import sys\n",
"import math\n",
"import time\n",
"import json\n",
"import random\n",
"import requests\n",
"import numpy as np\n",
"import seaborn as sns\n",
"import matplotlib as mpl\n",
"import matplotlib.pyplot as plt\n",
"import PIL\n",
"import cv2\n",
"import IPython.display\n",
"import cairosvg\n",
"import zstandard as zstd\n",
"from collections import namedtuple\n",
"from fastprogress.fastprogress import progress_bar\n",
"from matplotlib.gridspec import GridSpec\n",
"from matplotlib.path import Path\n",
"from mpl_toolkits.axes_grid1 import make_axes_locatable\n",
"from mpl_toolkits.mplot3d import Axes3D\n",
"\n",
"\n",
"sns.set('notebook', 'darkgrid', rc={\n",
" 'font.family': ['DejaVu Sans'],\n",
" 'font.sans-serif': ['Open Sans', 'Arial Unicode MS'],\n",
" 'font.size': 12,\n",
" 'figure.figsize': (8, 5),\n",
" 'grid.linewidth': 1,\n",
" 'grid.alpha': 0.5,\n",
" 'legend.fontsize': 10,\n",
" 'legend.frameon': True,\n",
" 'legend.framealpha': 0.6,\n",
" 'legend.handletextpad': 0.2,\n",
" 'lines.linewidth': 1,\n",
" 'axes.facecolor': '#fafafa',\n",
" 'axes.labelsize': 11,\n",
" 'axes.titlesize': 12,\n",
" 'axes.linewidth': 0.5,\n",
" 'xtick.labelsize': 11,\n",
" 'xtick.major.width': 0.5,\n",
" 'ytick.labelsize': 11,\n",
" 'ytick.major.width': 0.5,\n",
" 'figure.titlesize': 13,\n",
"})\n",
"plt.style.use(\"dark_background\")\n",
"\n",
"print(\"Infos:\")\n",
"print(\"numpy: {}\".format(np.__version__))\n",
"print(\"seaborn: {}\".format(sns.__version__))\n",
"print(\"matplotlib: {}\".format(mpl.__version__))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fonttools"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from fontTools.ttLib import TTFont\n",
"from fontTools.pens.recordingPen import RecordingPen\n",
"from fontTools.pens.svgPathPen import SVGPathPen\n",
"from fontTools.pens.ttGlyphPen import TTGlyphPen\n",
"from fontTools.pens.cu2quPen import Cu2QuPen\n",
"from fontTools.pens.areaPen import AreaPen"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def plot_svg(svg):\n",
" return IPython.display.HTML(svg)\n",
"\n",
"def get_glyph(font, char):\n",
" glyph_set = font.getGlyphSet()\n",
" cmap = font.getBestCmap() \n",
" return glyph_set[cmap[ord(char)]]\n",
"\n",
"def glyph_area(glyph):\n",
" pen = AreaPen()\n",
" glyph.draw(pen)\n",
" return pen.value\n",
"\n",
"def glyph2svg(font, glyph, size=512):\n",
" pen = SVGPathPen(font.getGlyphSet())\n",
" glyph.draw(pen)\n",
" \n",
" ascender, descender = font['hhea'].ascender, font['hhea'].descender\n",
" \n",
" width = glyph.width - glyph.lsb\n",
" extent = ascender - descender\n",
"\n",
" return f\"\"\"\n",
" <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 {extent} {extent}\" height=\"{size}\" width=\"{size}\">\n",
" <rect x=\"0\" y=\"0\" width=\"{extent}\" height=\"{extent}\" fill=\"black\"/>\n",
" <path transform=\"translate({(extent - width) / 2},{ascender}) scale(1,-1)\" d=\"{pen.getCommands()}\" fill=\"white\"/>\n",
" </svg>\n",
" \"\"\"\n",
"\n",
"def glyph2pil(font, glyph, size=512):\n",
" svg = glyph2svg(font, glyph, size)\n",
"\n",
" f = io.BytesIO()\n",
" cairosvg.svg2png(bytestring=svg.encode('utf-8'), write_to=f)\n",
"\n",
" return PIL.Image.open(f)\n",
"\n",
"def get_nonempty_glyph_codes(glyph_set):\n",
" codes = []\n",
" for key in progress_bar(glyph_set.keys()):\n",
" glyph = glyph_set[key]\n",
" if glyph.width > 0 and glyph_area(glyph_set[key]) > 0:\n",
" codes.append(key)\n",
" return codes"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"font = TTFont(\"images/Mplus1-Bold.otf\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <div>\n",
" <style>\n",
" /* Turns off some styling */\n",
" progress {\n",
" /* gets rid of default border in Firefox and Opera. */\n",
" border: none;\n",
" /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
" background-size: auto;\n",
" }\n",
" .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
" background: #F44336;\n",
" }\n",
" </style>\n",
" <progress value='6551' class='' max='6551' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" 100.00% [6551/6551 00:02<00:00]\n",
" </div>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"glyph_set = font.getGlyphSet()\n",
"codes = get_nonempty_glyph_codes(glyph_set)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1330 1330\" height=\"512\" width=\"512\">\n",
" <rect x=\"0\" y=\"0\" width=\"1330\" height=\"1330\" fill=\"black\"/>\n",
" <path transform=\"translate(344.5,1060) scale(1,-1)\" d=\"M221 780H450L573 1000H416L337 840H335L255 1000H98ZM407 0V607H641V730H28V607H262V0Z\" fill=\"white\"/>\n",
" </svg>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot_svg(glyph2svg(font, glyph_set['cid00159']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Slug"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"Curve = namedtuple('Curve', ['p1', 'p2', 'p3', 'first'], defaults=(None,None,None,False))\n",
"\n",
"def parse_points(string):\n",
" pts = list(map(float, string.split(\" \")))\n",
" return [(pts[i], pts[i + 1]) for i in range(0, len(pts), 2)]\n",
"\n",
"def eq_delta(a, b, eps=1e-5):\n",
" return abs(b - a) < eps\n",
"\n",
"def parse_path_data_to_curves(pd, snap_eps=.15):\n",
" cmds = re.findall(\"([A-Z][^A-Z]*)\", pd)\n",
" start = None\n",
" p1, first = None, True\n",
" curves = []\n",
" for cmd in cmds:\n",
" if cmd[0] == 'M':\n",
" pts = parse_points(cmd[1:])\n",
" p1, first = pts[0], True\n",
" start = p1\n",
" for p3 in pts[1:]:\n",
" p2 = ((p1[0] + p3[0]) / 2, (p1[1] + p3[1]) / 2)\n",
" curves.append(Curve(p1, p2, p3, first))\n",
" p1, first = p3, False\n",
" elif cmd[0] == 'L':\n",
" p3 = tuple(map(float, cmd[1:].split(' ')))\n",
" p2 = ((p1[0] + p3[0]) / 2, (p1[1] + p3[1]) / 2)\n",
" curves.append(Curve(p1, p2, p3, first))\n",
" p1, first = p3, False\n",
" elif cmd[0] == 'H':\n",
" p3 = (float(cmd[1:]), p1[1])\n",
" p2 = ((p1[0] + p3[0]) / 2, (p1[1] + p3[1]) / 2)\n",
" curves.append(Curve(p1, p2, p3, first))\n",
" p1, first = p3, False\n",
" elif cmd[0] == 'V':\n",
" p3 = (p1[0], float(cmd[1:]))\n",
" p2 = ((p1[0] + p3[0]) / 2, (p1[1] + p3[1]) / 2)\n",
" curves.append(Curve(p1, p2, p3, first))\n",
" p1, first = p3, False\n",
" elif cmd[0] == 'Q':\n",
" p2, p3 = parse_points(cmd[1:])\n",
" curves.append(Curve(p1, p2, p3, first))\n",
" p1, first = p3, False\n",
" elif cmd[0] == 'Z':\n",
" if p1[0] == start[0] and p1[1] == start[1]:\n",
" continue\n",
" p3 = start\n",
" p2 = ((p1[0] + p3[0]) / 2, (p1[1] + p3[1]) / 2)\n",
" curves.append(Curve(p1, p2, p3, False))\n",
" p1, first = None, True\n",
" else:\n",
" raise NotImplementedError(\"not supported: \" + cmd)\n",
" \n",
" if curves:\n",
" c = curves[-1]\n",
" if eq_delta(c.p1[0], c.p2[0]) and abs(c.p1[0] - c.p3[0]) < snap_eps:\n",
" c = Curve(c.p1, c.p2, (c.p1[0], c.p3[1]), c.first)\n",
" if eq_delta(c.p1[1], c.p2[1]) and abs(c.p1[1] - c.p3[1]) < snap_eps:\n",
" c = Curve(c.p1, c.p2, (c.p3[0], c.p1[1]), c.first)\n",
" curves[-1] = c\n",
" return curves\n",
"\n",
"def makePath(curves):\n",
" verts, codes = [], []\n",
" for c in curves:\n",
" if c.first or not codes:\n",
" verts.append(c.p1)\n",
" codes.append(Path.MOVETO)\n",
" verts.append(c.p2)\n",
" verts.append(c.p3)\n",
" codes.append(Path.CURVE3)\n",
" codes.append(Path.CURVE3)\n",
" return Path(verts, codes)\n",
"\n",
"class Glyph(object):\n",
" @staticmethod\n",
" def from_ttglyph(glyph, max_err=1.0):\n",
" pen = SVGPathPen(glyph._glyphset)\n",
" glyph.draw(Cu2QuPen(pen, max_err))\n",
" curves = parse_path_data_to_curves(pen.getCommands())\n",
" return Glyph(curves, glyph.width, glyph.lsb)\n",
" \n",
" def __init__(self, curves, width, lsb=0):\n",
" self.width = width\n",
" self.lsb = lsb\n",
" self.curves = curves\n",
" \n",
" def normalize_curves(self, ascender, descender):\n",
" extent = ascender - descender\n",
" xOff = (extent - (self.width - self.lsb)) / 2\n",
" res = []\n",
" for c in self.curves:\n",
" p1 = ((c.p1[0] - self.lsb + xOff) / extent, (c.p1[1] - descender) / extent)\n",
" p2 = ((c.p2[0] - self.lsb + xOff) / extent, (c.p2[1] - descender) / extent)\n",
" p3 = ((c.p3[0] - self.lsb + xOff) / extent, (c.p3[1] - descender) / extent)\n",
" res.append(Curve(p1, p2, p3, c.first))\n",
" return res\n",
" \n",
"def plot_curves(curves, n_bands=16):\n",
" fig, ax = plt.subplots(figsize=(8,8))\n",
" ax.add_patch(mpl.patches.PathPatch(makePath(curves), fc='gray', ec=\"white\", alpha=0.8))\n",
"\n",
" ax.set(xlim=(0, 1),ylim=(0, 1),aspect='equal')\n",
" ax.grid(which='minor', axis='both')\n",
" ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(1 / n_bands))\n",
" ax.xaxis.set_major_locator(mpl.ticker.MaxNLocator(4))\n",
" ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(1 / n_bands))\n",
" ax.yaxis.set_major_locator(mpl.ticker.MaxNLocator(4))\n",
"\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
"def plot_glyph(font, glyph, n_bands=16):\n",
" ascender, descender = font['hhea'].ascender, font['hhea'].descender\n",
" curves = Glyph.from_ttglyph(glyph, 1.0).normalize_curves(ascender, descender)\n",
" \n",
" plot_curves(curves)\n",
" \n",
" return curves"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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+i8dOHDgnH92zpw58ng86tGjh+Li4howJQDbxMXFKTs7WyUlJfrjH/8or9d7zj/7yiuv1F4SPiSEP70BAObwrxAAoNG48MILFRsbq507d+rVV189r5/Nzc3VihUrVFlZyX4cAM7LqFGjVFVVpZUrV2rVqlXn9bOfffaZvv32W0VFRalHjx4NExAAgHNAAQQAaBSSk5M1ePBglZSU6IknnlBlZeV5P0bNfhx9+/ZVREREA6QEYJsOHTqoU6dOOnr0qP7whz+c98/7fL7aY8+gQYPkcrkaICUAAD+OAggA0ChcfvnlKisr05tvvqmvv/66To/xw/04+vbt6894jhMaGsrpLLBeeHh47Wmns2bNUn5+fp0eZ/ny5Tpw4ICaNGmi9u3b+zmls4SHh1OiAUAd8ZcbANSRy+VSWlqakpKSTEexXu/evZWenq6DBw/qhRdeqNdj/f3vf5fX69XAgQMVGhrqp4TOc+GFF+o///M/demll5qO4jihoaFKT09XbGys6SjWGzp0qCIjI7Vt2zbNmzevzo9TWVmp119/XV6vV4MHD/ZjQucZM2aMfvnLXyorK8t0FABodCiAAKCORo4cqX/7t3/TZZddZjqK1WJjY3XxxRerpKREzz33nNxud70e77PPPtM333yjyMhI9uOoo7CwMPXv318VFRVq0qSJ6TiOM3HiRN18880aMmSI6ShWa9asmQYOHKiSkhI9/vjjqq6urtfjvfnmmzp69Khatmypli1b+imlsyQmJqpLly7y+XxKSEgwHQcAGh0KIACoh/LycrVu3VopKSmmo1jriiuukCR9+umneu+99/zymH//+9/Zj6MeevXqpdDQUFVVVZmO4kgul0tlZWXq1asXe1k1kNDQUI0bN06lpaWaO3eutm/fXu/H9Hq9WrhwobxerwYNGuSHlM4zYMAAlZeXy+fzmY4CAI0SBRAA1FNZWRlL0RtI79691a5dO+Xn52v69Ol+e9z3339f+/fvV2Jiorp27eq3x3UCl8ulgQMHntdlsOF/1dXV8vl86tOnj+koVho+fLgSEhK0a9cuzZgxw2+PO2/ePBUXF6tTp05KS0vz2+M6QWRkpPr06cOxBwDqgQIIAOqprKxMPXv2VGRkpOkoVklMTNSoUaNUXFysp59+WgUFBX577KqqKs2ePVsej0fDhg1jFdB56NChgxISElRRUWE6iuPVlM+8fv0rIyNDAwYMUHFxsR566CGVl5f77bELCwv1xhtvyOPxaPjw4X57XCfo27evfD5fvU/FAwAnowACgHqqrq5WdXW1unTpYjqKNVwul8aOHauKigq9//77WrZsmd+fY8mSJdq3b5/i4+PVq1cvvz++rS644AJ5vV6tX7/edBTHq6ioUFxcnDp06GA6ijXCw8M1duxYlZSU6L//+7/9curXv/qf//kfHTt2TO3bt1eLFi38/vg2CgkJUVZWFsceAKgnCiAAqKd169bJ6/WqR48efBLvJwMGDFDz5s114MABPfnkkw3yHFVVVfrrX/8qj8ejiy66iCuCnYNmzZqpVatWKioq0ltvvWU6juPVHHsGDBhgOoo1Ro0apcjISG3evFmzZ89ukOcoKirSa6+9Jo/Ho+zs7AZ5Dtt069ZNUVFR2rVrlz777DPTcQCg0aIAAoB6+vTTT2tXkrRp08Z0nEYvJSVFw4cPl9vt1u9//3sdP368wZ5r2bJl+uabbxQVFaXMzMwGex5bDBo0SF6vV4sXL1ZJSYnpOI731ltv6fjx42xE7ycdO3ZUr169VFRUpIcffliVlZUN9lxz5sxRQUGBWrVqpbZt2zbY89iiZuXha6+9xgbQAFAPFEAAUE/V1dWaP3++JHEqUT2FhIRo3LhxKisr0+LFi/XJJ5806PP5fD7NnDlTHo9HQ4cOVXh4eIM+X2MWHx+vrl27yuPxaO7cuabjQJLb7dbSpUtVVlbGKqB6io6O1pgxY+R2u/XnP/9Z+/bta9Dnc7vdeuWVV1gFdA7atGmjlJQUHTp0SO+++67pOADQqFEAAYAfvPPOO6qoqFB6ejpXdqmHIUOGKCkpSXv37tWf/vSngDzn6tWrtXnzZoWGhnI1t7OoufzyBx98oPz8fNNx8L/mz59fuxF9VFSU6TiN1uWXXy6Xy6UvvvhCr7/+ekCec968ecrLy1NaWpo6deoUkOdsjGpW/yxcuJDN5wGgniiAAMAPPB6PvvnmG0nik/g6Sk9P14UXXii3261HHnlEHo8nYM89Y8YMeTweDR48mKu5nUZERIQyMzPl9Xo1Z84c03HwA/v27dPatWtVVVXFaYx11KNHD3Xs2FFHjhzRI488ErBTjMrKyjR79myVlpYqOzubPeROIzk5We3bt5fb7dbChQtNxwGARo8CCAD8ZNu2bfL5fOrevbtiYmJMx2lUwsLCNG7cOJWWlurVV1/Vxo0bA/r869at0xdffCHpn58242Q1xcJXX32lHTt2mA2DU8ybN09er1f9+/enRDhP8fHxuvTSS+V2u/XMM88oLy8voM+/ePFiff/992rSpIm6d+8e0OduDGpW/yxZsqRB94MDAKegAAIAPzl+/Lhyc3P5JL4ORowYodjYWO3YsUMzZ840kmHmzJkqLS3VgAEDKPB+wOVyacCAAaz+CWKffvqpcnJyFBMTo86dO5uO06hceeWVqq6u1sqVK7VkyZKAP39FRYVeeukllZaWatiwYQoJ4U/zGjExMerRo0ft5s8AgPrjXxkA8KOtW7fK6/WqX79+/CF/jtq2bat+/frp+PHjevjhh43t8bBlyxatXr1a1dXVuvDCC41kCEZdu3ZVdHS09uzZ0+CbcqNufD6f5s+fzyXhz1P//v3VqlUr5eXl6bHHHjOWY+nSpdq9e7diY2PVp08fYzmCTf/+/VVZWanVq1crNzfXdBwAsALvTgDAj/bv369du3YpKipKXbp0MR0n6MXGxuqqq66S2+3WSy+9VLuPkimzZs2Sx+NR3759lZCQYDRLsODyy43DkiVLVFRUpJYtW7IR/Tlo1qyZLr74Yrndbj3xxBMqLCw0lqW6ulp/+ctfVFpaqiFDhigsLMxYlmARFham/v37s/IQAPyMAggA/IxP4s+Ny+XSNddcI0lau3atXn75ZcOJpF27dmnZsmWqqKjQ0KFDTccxLiMjQ2lpaTp8+LCWLl1qOg7OwuPx6J133uGS8OcgMjJS48ePl9fr1YIFC7RixQrTkfTRRx9p+/btioyMVP/+/U3HMa5Xr14KDQ3Vli1bAr4nHADYjAIIAPxs6dKlOnr0qNLT05Wenm46TtAaNmyYmjdvrv379+u3v/1t0Kwu+ctf/iK3261evXqpWbNmpuMYNWjQoNrLL584ccJ0HPyImvKZjejPbsyYMYqKitLmzZv17LPPmo4j6Z+n8c2YMaN2FZCT//u5XK7alYes/gEA/2KNqZ9NmzbNdAQjsrOzTUcwLpBz0Lx5c6WmpqqqqipoCob4+HjTEQIuISFBSUlJmjBhgjp37nzSa6CsrExRUVEaMWKEVq5caS5kAJ3PayAjI0PZ2dny+XzKycnR3Xff3YDJzl9hYaFatWqla665RkuWLDmncsq234HExER169ZN1dXVat++/Sn/vrVu3VopKSnyeDy1xyHb5uB8BWr8MTExSklJ0W233aZLL730pO9VVFQoJiZG2dnZRlZOBPtroGfPnurVq5dOnDih/Px8/eY3v/Hr49f3b4ETJ06oWbNmGjdunFavXu2fUAFW39dAmzZt1KxZM5WUlGjIkCGn7MnWp08fJSUlKSEhIWj+BvqhYP8d8Jfo6GilpqbqzjvvVH5+/knfc/r7AsafbTqCccE8B6wAAoAGsH37dvl8PnXo0EHR0dGm4wSV2NhYjRgxQtI/Lyt+8OBBw4lOtX79enm9XjVr1kydOnUyHceIXr16yeVyadeuXfJ6vabj4Bxt3bpVktS9e3c2ov8XqampGjRokCRp9erVKi4uNpzoVJ999pmqqqrUpUsXx+7l1Lt3b0n/3Jg/WFaGAoAtWAHkZ9OnTzcdwSinj18KzBxkZmZq8ODB8ng8ysvLa/DnOx/BlqchFRcXq6ioSIsWLdLcuXNrv17zGqiurtbYsWPVsmVLffzxx6ZiBtzZXgMhISG66aabVFZWpqVLl+qXv/xl0P6B/+mnn+qJJ55QZmamPv/8c5WXl5/Tz9nwOxAdHa22bdvq0KFDuu2225STk3PKfYYOHaqsrCyVlpaeMmYb5qA+Gnr8Ho9HR44c0ezZs7V27dpTvr9gwQJlZmYqISFBO3bsaNAsZxJsr4GoqCiNHz9ehYWFeuWVVxr81K/6/C2we/du3XHHHerXr5/+9re/Be0x8sfU5TXQvHlzJSUladeuXfrJT34ij8dzyn0mT56szp07q7i4OOheZz8UzNn8wev1qqCgQLNmzdKWLVtOex+nvy9g/M4ef7CuAuKjIQBoIPPmzau9JHxoaKjpOEFh+PDhSktLU05Ojh5++OGgfmPz3nvvaf369QoJCdFFF11kOk5A9evXT5WVlfr4449PW/4guLER/clcLpfGjh2r8PBwbdy4Uf/v//0/05HO6uWXX1Zubq6Sk5OVmZlpOk5A1ez9s3jx4tOWPwCA+qEAAoAGsmHDBu3cuVPh4eHq1q2b6TjGderUSQMHDtTx48f14IMP6tixY6Yj/ainn35aJSUl6t+/v1JSUkzHCYjQ0FBlZWWxAWsjtnTpUhUWFrIR/f+64IILale0Pfjgg6qsrDQd6azKysr03HPPqbS0VNnZ2YqKijIdKSASEhLUtWtXeTwezZs3z3QcALASBRAANKCaVUBO/yQ+MTFRV155pYqLi/Xiiy9q8+bNpiOdk127dmnBggXyer0aPXq06TgB0bNnT4WFhWnHjh366quvTMdBHZSVlemtt96S1+tVVlaW6ThGtWrVSsOHD1dxcbGmTZvWaE7L+fDDD2tP7xs+fLjhNIExYMAAlZeX6/333z9lU2EAgH9QAAFAA1q2bJkKCgqUmpqqli1bmo5jREhIiK655hpVVVVp5cqVjW5VyV/+8hfl5eWpZcuW1q/k4vLL9liwYIE8Ho+6deum2NhY03GMiImJ0dVXX62SkhL9/e9/b3R7sf3xj39UcXGxMjMz1axZM9NxGlRkZKQyMzM59gBAA6MAAoAGdOLECb355psqKytz7Cqgiy++WMnJydq3b5+mTZsW1Pv+nI7b7daMGTNUUlKiSy65ROHh4aYjNZj27durSZMmOnDggN5//33TcVAPeXl5Wr16tSoqKtSvXz/TcQLO5XJp3LhxCgsL01dffaU///nPpiOdt3379mnu3LnyeDwaPXq0XC6X6UgNJjMzUz6fT+vWrdPOnTtNxwEAa1EAAUADW7hwoTwej7p06aL4+HjTcQKqW7du6t+/v4qKijR16lS53W7TkepkyZIl+vrrrxUeHq6hQ4eajtNgLrjggtr9N6qqqkzHQT3NnTvXsRvRDxkyRK1atdLBgwc1derURvt6fumll3Tw4EE1a9ZMPXv2NB2nQYSEhGjAgAGs/gGAAKAAAoAGVlBQoA8//FAnTpxQ//79TccJmLS0NI0ZM0bFxcV67rnntG3bNtOR6szn8+npp59WaWmpBgwYoKZNm5qO5HdpaWnKyMhQUVGRFi9ebDoO/MCpG9F36tRJQ4YMUXFxsR566CEVFBSYjlRnHo9Hzz//vEpKSnTxxRcrMjLSdCS/69q1q6KiorRnzx59+umnpuMAgNUogAAgAGo+ic/MzFRYWJjpOA0uJiZGkyZNqt2Mdv78+aYj1dv27du1ePFilZWVWbkhdM3eP2+99ZZKSkpMx4GfOG0j+pSUFI0bN07FxcV64YUXajdSbszee+89rV+/XiEhIVZuCF1z7Hnttdca3SnCANDYUAABQABs2bJFW7ZsUWhoqHr06GE6ToMKCQnR+PHjFR4erg0bNuiJJ54wHclvZsyYofz8fLVq1Up9+/Y1Hcdv4uPj1b17dy6/bCEnbUQfFRWlSZMmqby8XO+++65eeeUV05H85umnn5bb7Vbfvn2VkZFhOo7fZGRkKDU1Vfn5+Vq6dKnpOABgPQogAAgQp3wSf8kll6hZs2b67rvvdO+996qiosJ0JL85duxY7Ruxiy++WImJiaYj+UVWVpbKy8v14YcfNprLZOPcOGUjepfLpWuuuUaRkZHavHmzHn30UdOR/GrXrl2aPXu2SkpKNHbsWGs2ox80aJC8Xq8WLlyoEydOmI4DANajAAKAAPnwww+Vn5+vpk2bqnXr1qbjNIiuXbsqMzNThYWFuu+++3TkyBHTkfzu/fff1/vvv6+KigqNHTu20V+ZJzw8XH379mUDVos5YSP6iy++WC1bttT+/ft1zz33qLy83HQkv5s9e7a2bt2qqKgoXXLJJabj1FvTpk3VoUMHud1uvfHGG6bjAIAjUAABQIBUVFTojTfesHYVUHp6uoYOHari4mI98cQT2rp1q+lIDeapp57SgQMHlJ6erqysLNNx6iUzM1Mul0sbNmzQ9u3bTcdBA7B9I/revXvXXm3w/vvvV35+vulIDaKyslIPP/ywjh07pt69e6t9+/amI9VLzd4///jHP1RUVGQ6DgA4AgUQAATQokWLVFpaqo4dO1pz+pAkJSUl6dJLL1VISIheffVVvfPOO6YjNahjx47piSeekNvtVnZ2dqO9KpjL5dKAAQPk8XhY/WM5Wzeib9OmjS677DIVFxfrySef1KZNm0xHalB79uzRrFmz5Ha7dcUVVzTaq4LFxMSoZ8+eKisr02uvvWY6DgA4BgUQAARQYWGhli9frvLy8ka/cqRGdHS0rrvuOkVGRuq7777T888/bzpSQKxevVrvvPOOysvLG+2pYF27dlVsbKz27dunNWvWmI6DBrRlyxZt3brVqo3ok5OTNX78eJWUlOhvf/ub3nrrLdORAuLVV1/Vxo0bFR4erksvvdR0nDrp37+/KisrtWbNGn333Xem4wCAY1AAAUCA1WwG3adPn0a/kWdoaKgmTJigqKgoHTlyRCtWrHDUZXyfeeYZfffdd0pNTVWfPn1MxzlvF1xwgTwej15//XVH/XdzqppVQDacghoTE6Nrr71WlZWVev/99/Xiiy+ajhQw1dXVmjZtmoqKitStWzd16tTJdKTzEhoaqn79+rHvGAAYQAEEAAG2Y8cObdq0SS6XS7169TIdp16uuOIKNWvWTPv27dPy5cutuuLXuXC73fr9738vt9ut/v37N6pTwVq1aqW0tDQdOXJE//jHP0zHQQDYshF9aGioJk6cqMjISG3YsEEPPfSQ4wrM77//Xi+88IJKSkp0xRVXKDo62nSkc9arVy+FhYVp+/btWr9+vek4AOAoFEAAYEDNKqCsrKxGeeqQJF100UXq2rWrDh8+rF/96lcqLS01HcmIzz//XG+88YZCQ0OVnZ2tkJDG8U9rzQasb7zxhsrKykzHQQDYsBG9y+XS2LFjlZKSor179+rXv/61lVf8Ohfz58/XF198IZfLpcsvv9x0nHPicrk0cOBAVv8AgCGN469UALDMihUrdODAATVp0kRt27Y1Hee89evXT4MHD9axY8f0m9/8Rrt27TIdyajnn39ebrdbKSkpGjJkiOk4PyopKUkdO3ZUSUmJ5s+fbzoOAqixb0Q/atQodezYsbZ4Pnr0qOlIxvh8Pj3yyCM6cuSIOnbsqG7dupmO9KPat2+vxMREHThwQB988IHpOADgOBRAAGBAVVVVo/0kvkePHho1apSOHz+uxx57TB9//LHpSMZ5vV6tWrVKknThhReqZcuWZgP9iIEDB6q8vFzvvvuuCgsLTcdBADXmjegvuugi9enTR0ePHtWvf/1r7d6923Qk4/Ly8vTcc8/J7XbrsssuU0JCgulIZ1Wz8nDevHmqqqoyHQcAHIcCCAAMefPNN+V2u9W+fXslJSWZjnNOOnTooDFjxuj48eN6/vnn9fbbb5uOFDTy8vK0efNmlZSUaPz48YqJiTEd6bSioqLUu3dveb1eLr/sUI1xI/qsrKzaVYdTp07VV199ZTpS0Fi8eLFWrVqlqqoqjR8/XqGhoaYjnVazZs2UkZGhoqIiLV682HQcAHAkCiAAMOT48eN67733VFZW1ihWAbVq1Urjx4+X2+3Wyy+/rFdffdV0pKDz5Zdf6ssvv1RISIiuueaaoNzfqV+/fqqqqtKnn36qvXv3mo4DAxrbRvQ9e/bUyJEjdfz4cU2fPl2rV682HSnoPPzww9qzZ4+Sk5OD9tLwNat/3nrrLZWUlJiOAwCORAEEAAbVfBLfq1cvRUREmI5zRmlpabr22mtVWlqqhQsXasaMGaYjBaXq6mpNnTpVubm5Sk9PV3Z2tulIJwkNDVVWVpY8Hg8FnsP9cCP6YNapU6faVYfPPvssV6w7A7fbrfvvv19Hjx5Vr1691Lt3b9ORThIfH69u3brJ4/Fo3rx5puMAgGNRAAGAQbt27dJXX30ln8+nPn36mI5zWklJSbrhhht04sQJLVu2TE8++aTpSEHt6NGjmjp1qo4dO6aBAweqS5cupiPV6tGjhyIiIrRz506tW7fOdBwY9MON6Nu1a2c6zmllZGTo6quvVnFxsf7rv/5Lr7/+uulIQe2bb77Rk08+qeLiYo0ePVrNmjUzHalWVlaWysvL9cEHHygvL890HABwLAogADBs7ty5KisrC8pLwsfHx+vGG29UdXW11qxZo4ceekg+n890rKC3adMmPf/88youLtaVV16ppk2bmo4k6Z+nYHg8Hi6/jKDfiL5Zs2aaNGmSSktLtWDBAs2aNct0pEbhnXfeqf3vOmHCBEVFRZmOpPDwcPXt25dLvwNAEKAAAgDDVq9ere+//15xcXHq0KGD6Ti1oqKidP311ys0NFRfffWV7rvvPlVUVJiO1Wi8/vrrWrZsmU6cOKEJEyYY32y3ZrPxgwcP6v333zeaBcEhWDeiT0pK0vXXX6/y8nItXbpUTz31lOlIjcof//hHbdq0SREREbrqqquMf7CQmZkpSVq/fr127NhhNAsAOB0FEAAY5vP5tGDBgqD6JD48PFzXXXedYmNjtW3bNv3yl7+U1+s1HavRefTRR7Vz507FxcVpzJgxRrPUbMA6f/58VVZWGs2C4BCMG9H/cNXh6tWrNW3aNFYdnqeKigrdf//9ysvLU0ZGhoYOHWosi8vl0sCBA1n9AwBBggIIAILA22+/rePHj6t169ZKSUkxmiU0NFQTJ05U06ZNtWvXLv385z9XcXGx0UyNldfr1X333aeCggJ16tTJ2JvstLQ0tW7dWkVFRXrzzTeNZEBwCqaN6KOjo3XDDTcoNDRUX375pe6//37Kyjo6dOiQfvOb36i4uFgXXnih2rdvbyRH165dFRMTo7179+rjjz82kgEA8H8ogAAgCLjdbi1dutT4J/FhYWG69tprlZ6eru+//14///nPVVBQYCyPDXJycvTII4+ouLhYI0aMUKtWrQKeYeDAgSorK9OSJUvkdrsD/vwIXsGyEX1sbKxuvvlmRUdHa+vWrfrVr36lsrIyY3ls8MUXX2jmzJlyu9266qqrlJiYGPAMNfuOvf7666zkAoAgQAEEAEFi/vz5KisrU8+ePY1s3BkeHq7rr7++tvyZMmWKcnNzA57DRitWrNArr7yi0tJSTZgwQU2aNAnYc8fFxal79+4qLS3lKko4LdMb0cfHx2vy5MmKiYnR1q1bNWXKFIpKP/mf//kfrVixQlVVVZo0aZIiIyMD9tytWrVSWlqaCgoK9I9//CNgzwsAODMKIAAIEvv27dPatWtVVVVVu2lmoERGRurGG29Uamqq9u7dq9tvv127d+8OaAbbvfjii/rkk09UXV2t66+/XjExMQF53qysLFVUVGjlypU6ePBgQJ4TjYvJjegTExM1efJkRUREaNOmTfrZz36mo0ePBjSDzXw+nx5++GHt3LlT8fHxmjRpkkJDQwPy3DX7jr3xxhsqLy8PyHMCAM6OAggAgsjcuXPl9XrVv3//gH0SHx0drZtuuklJSUnavXu3br/9dn333XcBeW4nqa6u1n333aevv/5akZGRuvbaaxv8ymBcfhnnwtRG9ElJSZo8eXLtlQbvuOMOHTt2LGDP7xQlJSX6+c9/rpycHKWlpQXkymCJiYnq2LGjSkpKtGDBggZ9LgDAuaMAAoAg8tlnn2nfvn2KiYlR586dG/z5avbdSEhI0DfffKN///d/14EDBxr8eZ3K4/HoF7/4hXbv3q2kpCRNmDBBISEN909x7969FRISoo0bN2rLli0N9jxo/AK9EX1KSop+8pOfyOVy6fPPP9ddd93FaV8N6NChQ7r77ruVl5en9u3b69JLL23Q5+vZs6fKy8v17rvvqrCwsEGfCwBw7iiAACCI+Hw+zZ8/PyCfxP/rvhu333678vPzG/Q5IRUWFtbur9SyZUtdeeWVDfJpPJdfxvkI5Eb0zZo1080336yqqiqtWbNGd999tzweT4M+J6Tdu3fr17/+tY4cOaI+ffpoyJAhDfI8kZGR6tKlC8ceAAhCFEAAEGTeeecdFRUVqWXLlkpLS2uQ5zjdvhtHjhxpkOfCqfbv369f/vKXOnz4sLp06aIRI0b4/Tk6d+6suLg45eTkaNWqVX5/fNgnEBvRt2jRQjfddJMqKir00UcfcbWvANu4caN++9vf6tixYxo6dGiDXPmte/fuCgsL0yeffKJ9+/b5/fEBAHVHAQQAQcbj8WjJkiUN9kl8zb4bYWFhWr9+ve644w4VFRX5/Xlwdjt27NC9996rwsJCZWVlaeDAgX59/JoNWLn8Ms5VQ29En5GRoRtuuEHl5eVatmyZ7rvvPlVUVPj9eXB2K1eu1JNPPqnjx49r9OjR6tSpk98eOzQ0VD169JAkVv8AQBCiAAKAIFSzIWv37t39erWolJQUTZ48uXbfjTvvvJN9Nwz64osvNG3aNB0/flwjRoyofeNUXy1atFB6erqOHDmid955xy+PCWeYN29eg2xE37ZtW1133XXyer1asmSJHnzwQVVWVvrt8XF+Fi1apL/+9a9yu926+uqr1apVK788bo8ePRQTE6OjR49q3bp1fnlMAID/UAABQBDKzc3Vxx9/rMrKSr99Ep+RkaGbb75Z1dXV+vjjj9l3I0gsW7ZMzz77rI4fP64xY8aoXbt29X7MQYMGyev1atGiRfJ6vX5ICaf49NNP/b4Rfffu3TVp0iR5PB4tWrRIDz/8sKqrq/3y2Ki7v/71r1q4cKE8Ho8mTZrkl82/L7jgAknS5s2b6/1YAAD/owACgCA1d+5clZWVqX///vW+UlTPnj11/fXXn7TvBsVA8Hj99df1t7/9TSUlJZowYYLatm1b58dKTExUp06dVFJSovnz5/svJBzB3xvRX3TRRRo7dqxKSko0Z84cPfbYY5ySGESeeuopffjhh6qoqNCNN95YrxKoffv2SkpKUmlpqfbs2ePHlAAAf6EAAoAg9eWXX2rXrl21V1Spq2HDhmnMmDFyu9169dVXdc899+jEiRN+TAp/ePHFF/XGG2/Ufhpf1305Bg4cWLvHCht7oy78sRF9aGioxo0bp0GDBqmoqEhPP/20nnnmGcqfIFNdXa0HH3xQn3zyiaqrqzV58mSlp6fX6bFq9h3btm0bK7wAIEhRAAFAEKvZj6MuGwSHhobqqquu0gUXXKDCwkI9+eSTeuaZZ/jDPEj5fD49/vjjevXVV1VSUqLx48ef955AUVFR6tOnj7xer1577bUGSgrb1Xcj+qioKN14443q1KmTDh06pP/8z//UvHnzGiAp/OHEiRP65S9/qQ8//FAnTpzQjTfeqIyM/9/enUdHUeb7H/90d7oDhCQsAUEJSkAQRTEKHHFBENErI6iIC+ooLscZwUE9Z9y4enMZx4XRUc+M4MAcB5cZ0IvgyFxUXC4BVFQQUVQUUCJBgoGQQNJL0t15fn/46wwhCSSdTle66v0653sSqqsr36ewys6Hp6pyW7SNnj17qm/fviovL9fmzZvbqFMAQGsRAAFAO/bGG2+orKxMvXr1atG/ynbq1EnXXnut+vfvr5KSEt1xxx1avHhxG3aKRDDG6I9//KPmz5+v/fv36+KLL1Z+fn6z33/qqaeqtrZWH330kbZu3dqGncLu4r0RfZcuXXTppZeqe/fu2rZtm2666SatWbOmDTtFIoTDYd1999363//9XwWDQV111VUtuh/ZiBEjFAqFtGzZMlVXV7dhpwCA1iAAAoB2LBQK6Z///GeL7seRk5OjqVOnqmvXrnW/gH344Ydt3CkS6dlnn9XTTz+tiooKXXDBBXU3Vj0ct9ut4cOHKxgM8vhltFrsRvQteST8cccdp0suuURZWVlav369brjhBoLIFBKNRvXAAw9oyZIlCgQCmjx5crNuBN65c2edeOKJ8vv9WrhwYRI6BQDEiwAIANq52FNaTjjhBGVkZBx23eOOO07XX3+93G631q9fr+uvv17btm1LUqdIpBdffFGPPvqoKioqdO655+qcc8457Ponnnii0tPTtWXLFq1duzZJXcLODn4k/JFuRD906FBdeeWVSk9PV1FRkW699VbuQZWCjDH6/e9/rxdffFFVVVW67LLLNGTIkMO+Z9iwYQqHw1q5cqV27dqVpE4BAPEgAAKAdq6kpESFhYUKh8M67bTTmlwvPz9fV111lUKhkN544w3deuut2rdvXxI7RaK9+uqrevDBB1VeXq6RI0fq/PPPb3Ld2A1Ymf2DRPn444+PeCN6l8ulMWPG6MILL9SBAwf0+eef65133lEoFEpyt0gUY4yefPJJ/eUvf9H+/fv1i1/8oslLUb1er/Lz8xUIBDj3AEAKIAACgBQQ+5f40047TR6Pp95rLpdL559/vsaNG6f9+/dr/vz5uv/++7kPg0288cYbuueee7R3717l5+dr/Pjxcrlc9dY57rjj1L17d+3evVtvvfWWRZ3Cjg73SHiv16tJkybp9NNPV1lZmWbNmqWPP/6YJ33ZxLx58/TUU0/VXYp6xhlnNFjnlFNOkdvt1saNG7Vp0yYLugQAtAQBEACkgA0bNuibb76R1+vV4MGD65ZnZGTo2muv1amnnqq9e/eqoKBAc+fO5Rcwm1m5cqXuuusu7dmzRyeeeKImT54sr9db93ps9s8rr7yicDhsYaewm+XLl2vfvn3q3bt3vRvR5+Tk6KabblLfvn31448/6vbbb9frr79uYadoCy+99JIefvhhlZeXa9SoUbrgggvqAmiXy6URI0Yw8xAAUggBEACkiNgsoNi/xOfm5uqWW25R9+7d9d133+nXv/61/vWvf1ncJdrK2rVrNW3aNBUXF6tPnz6aOnWqsrOzlZOTo379+unAgQN69dVXrW4TNnPwjeiHDRsmSTrppJM0depUeb1effHFF7rhhhu0bt06iztFW1m6dKlmzpypPXv26JRTTtFVV12l9PR0DRw4UJ07d1ZRUZEKCwutbhMA0AwEQACQIt566y3t2bNHPXr00Pjx43XNNdcoEolozZo1uvbaa7Vx40arW0Qb27hxo2644QZ9+eWX6tixo6ZOnaoLLrhAwWBQy5Yt04EDB6xuETb0P//zPwoEAho8eLAuvvhi/eIXv5Df79drr72mG264QTt27LC6RbSxt99+W7feequKiorUq1cvTZ06VWeffbaCwaAWLlzIrFMASBEEQACQImpqarRkyRKFQiGddNJJqqio0Lx58zRt2jRu9uwgO3fu1I033qiVK1cqEokoNzdXgUCAxy+jzRx8I/pBgwZpz549+t3vfqeCggJu9uwgmzZt0vXXX6/PP/9cPp9P3bt31969e5l5CgAphAAIAFLIq6++qkAgoOLiYt15552aO3euamtrrW4LSVZVVaU77rhDL730ksrLy7Vq1SoVFxdb3RZs7OWXX5bf79e3336rm266Sa+99prVLcECu3fv1k033aS3335bFRUVWrJkiYLBoNVtAQCaKc3qBgAAzbdnzx49++yzWrFihXbt2mV1O7BQbW2tnnjiCX3//ffatm2b1e3A5jZs2KAXX3xRCxYsUGVlpdXtwELBYFC//e1vNW3aNL3yyitWtwMLcekfkHoIgAAgxSxYsMDqFtCOLF261OoW4BB/+tOfrG4B7YQxRnPmzLG6DVgo9jQ4ZiEDqYVLwAAAAAAAzUYABKQmAiAAAAAAKcHt/vnXFy4/slbs74EACEgtBEAAAAAAUoLH45HL5SJ4sBgzgIDURAAEAAAAICWkpf18C1OCB2u5XC4ZYxSNRq1uBUALJDQAmjJlilavXq2KigpVVlZq3bp1mjZtWl1C3Bwul0sjR47UQw89pA8++ED79u1TTU2Ndu/ereXLl+uSSy5p8r0FBQUyxjRZPKYSAAAASF1paWly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0GWXXaYtW7bo9ddfl8/n0z333KP169erR48eiRguAAAAAABAykhIADRp0iRNnz5dJSUlOuWUUzRhwgRNmjRJxx9/vL7++mtNmjRJv/nNb5q9vdNPP12PPfaY/H6/zjrrLI0bN05XXnml8vLytGrVKo0cOVIPP/xwg/cdc8wxeu655+RyuXTJJZfonHPO0dVXX63+/fvr5Zdf1vHHH6958+YlYsgAAAAAAAApIyEB0P333y9Juvfee7Vt27a65aWlpbrtttskSffdd1+zZwHdd999crvdmj17tj755JO65X6/XzfeeKOi0aimTZum7Ozseu+788471alTJ73wwgtatmxZ3fJoNKpbb71V+/fv12WXXabBgwfHPVYAAAAAAIBU0+oA6JhjjtGwYcNUXV2txYsXN3h99erV2rlzp3r37q0zzjjjiNvzer266KKLJEn/+Mc/Gry+fft2rV27Vunp6Ro/fny91y699NIm31dZWal//etf9dYDAAAAAABwglYHQPn5+ZKkr776SqFQqNF11q1bV2/dwxk0aJAyMjJUVlam77//vtnby8zM1IABA+q93po+AAAAAAAA7KLVAVC/fv0kST/88EOT6+zYsaPeus3ZXuw9zd3ecccdJ0kqLy9XZWVlq/sAAAAAAACwi7TWbqBz586Sfr4/T1Oqqqok/TxLp622l+g+4lVQUNBm227PRo8ebXULlnP6PnD6+CX2AeMfbXULlnP6PnD6+CX2gdPHL7EPnD5+iX3A+Edb3YLl2vM+aHUAhPr++7//2+oWLNWe/2NPFqfvA6ePX2IfMP7RVrdgOafvA6ePX2IfOH38EvvA6eOX2AeMf7TVLaARrQ6AYrNqMjIymlwnNjunqUuzErG9RPcRj+Y+5QwAAAAAACCZWn0PoKKiIknSscce2+Q6ubm59dZtzvb69u3bou3F7kHUtWvXJi/xakkfAAAAAAAAdtHqAOizzz6TJJ100knq0KFDo+sMHz683rqH88033ygQCKh79+7Ky8trdJ0RI0Y02N6BAwe0bdu2ej+vOe8DAAAAAACwu1YHQDt37tSnn36q9PR0XXHFFQ1eHzVqlHJzc1VSUqK1a9cecXvhcFhvvvmmJOnaa69t8Hq/fv00cuRIVVdXa/ny5fVee/3115t8X2ZmpiZMmCBJeu211448MAAAAAAAABsxra3LL7/cGGPM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\n",
"text/plain": [
"<Figure size 576x576 with 1 Axes>"
]
},
"metadata": {
"image/png": {
"height": 553,
"width": 576
}
},
"output_type": "display_data"
}
],
"source": [
"curves = plot_glyph(font, glyph_set[random.sample(codes, 1)[0]])"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"class RangeQuantizer(object):\n",
" def __init__(self, alpha, beta, dtype=np.uint16):\n",
" self.dtype = dtype\n",
" iinfo = np.iinfo(dtype)\n",
" self.alpha_q, self.beta_q = iinfo.min, iinfo.max\n",
" self.s = (beta - alpha) / (self.beta_q - self.alpha_q)\n",
" self.z = round((beta * self.alpha_q - alpha * self.beta_q) / (beta - alpha))\n",
"\n",
" def quantize(self, x):\n",
" x_q = np.round(1 / self.s * x + self.z)\n",
" return np.clip(x_q, self.alpha_q, self.beta_q).astype(self.dtype)\n",
"\n",
" def dequantize(self, x_q):\n",
" return self.s * (x_q.astype(np.float32) - self.z)\n",
"\n",
"class GlyphSet(object):\n",
" def __init__(self, font, n_bands=16):\n",
" self.ascender = font['hhea'].ascender\n",
" self.descender = font['hhea'].descender\n",
" cmap = font.getBestCmap()\n",
" self.code2unicode = {v: k for k, v in cmap.items()}\n",
" self.curvesData = []\n",
" self.glyphs = []\n",
" self.n_bands = n_bands\n",
" \n",
" def add(self, code, glyph):\n",
" data = self.curvesData\n",
"\n",
" unicode = self.code2unicode.get(code, '')\n",
" curves = glyph.normalize_curves(self.ascender, self.descender)\n",
" offset = math.ceil(len(data) / 4) * 4\n",
" meta = {\"code\": code, \"unicode\": unicode, \"width\": glyph.width, \n",
" \"offset\": offset, \"num_curves\": len(curves)}\n",
" self.glyphs.append(meta)\n",
" \n",
" for c in curves:\n",
" if c.first and len(data) % 4 != 0:\n",
" data.append(1)\n",
" data.append(1)\n",
" if c.first:\n",
" data.append(c.p1[0])\n",
" data.append(c.p1[1])\n",
" data.append(c.p2[0])\n",
" data.append(c.p2[1])\n",
" data.append(c.p3[0])\n",
" data.append(c.p3[1])\n",
" \n",
" def export(self):\n",
" quantizer = RangeQuantizer(0, 1, np.uint16)\n",
" cctx = zstd.ZstdCompressor(level=22)\n",
" raw = quantizer.quantize(np.array(self.curvesData, np.float32))\n",
" return cctx.compress(raw.tobytes())"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <div>\n",
" <style>\n",
" /* Turns off some styling */\n",
" progress {\n",
" /* gets rid of default border in Firefox and Opera. */\n",
" border: none;\n",
" /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
" background-size: auto;\n",
" }\n",
" .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
" background: #F44336;\n",
" }\n",
" </style>\n",
" <progress value='3000' class='' max='3000' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" 100.00% [3000/3000 00:02<00:00]\n",
" </div>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
" <div>\n",
" <style>\n",
" /* Turns off some styling */\n",
" progress {\n",
" /* gets rid of default border in Firefox and Opera. */\n",
" border: none;\n",
" /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
" background-size: auto;\n",
" }\n",
" .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
" background: #F44336;\n",
" }\n",
" </style>\n",
" <progress value='3000' class='' max='3000' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" 100.00% [3000/3000 00:03<00:00]\n",
" </div>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
" <div>\n",
" <style>\n",
" /* Turns off some styling */\n",
" progress {\n",
" /* gets rid of default border in Firefox and Opera. */\n",
" border: none;\n",
" /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
" background-size: auto;\n",
" }\n",
" .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
" background: #F44336;\n",
" }\n",
" </style>\n",
" <progress value='521' class='' max='521' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" 100.00% [521/521 00:00<00:00]\n",
" </div>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"batch_size = 3000\n",
"n_batches = math.ceil(len(codes) / batch_size)\n",
"\n",
"glyph_sets = []\n",
"\n",
"for b in range(n_batches):\n",
" gs = GlyphSet(font)\n",
" batch = codes[b * batch_size:(b + 1) * batch_size]\n",
" for code in progress_bar(batch):\n",
" gs.add(code, Glyph.from_ttglyph(glyph_set[code], 1.0))\n",
" glyph_sets.append(gs)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"name = \"Mplus1-Bold\"\n",
"\n",
"glyphs = []\n",
"for i, gs in enumerate(glyph_sets):\n",
" glyphs.append(gs.glyphs)\n",
" with open(\"temp/{}_data_{}.bin\".format(name, i), \"wb\") as f:\n",
" f.write(gs.export())\n",
" \n",
"with open(\"temp/{}_glyphs.json.zst\".format(name), \"wb\") as f:\n",
" raw = bytearray(json.dumps(glyphs), 'utf-8')\n",
" cctx = zstd.ZstdCompressor(level=22)\n",
" f.write(cctx.compress(raw))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment