char/iocgn-mono

iosevka variant inspired by Simple Köln-Bonn

git clone https://git.t4t.associates/char/iocgn-mono

Charlotte Somsimplify pipeline even more (less python!! :D)2ba32a9

main
4.1 KiB72 linesraw
1"""Render a weight sweep and compare variable endpoints against static references."""
2
3import hashlib
4import json
5from pathlib import Path
6
7from fontTools.ttLib import TTFont
8from fontTools.varLib.instancer import instantiateVariableFont
9from PIL import Image, ImageChops, ImageDraw, ImageFont, ImageStat
10
11from render import ROOT, code_mask
12
13
14def main():
15    output = ROOT / 'build/variable'
16    path = ROOT / 'build/TTF/iocgnMono-Variable.ttf'
17    sweep = Image.new('RGB', (2200, 3640), '#fafafa')
18    rows = [('Hno mWw r g 0O1Il| \'"`', 110, 165),
19            ('comment format com rma minimum WWWW wwww mmmm', 48, 255),
20            ('const row = `${name}: ${count}`; // + - = * < > ()[]{}', 42, 325),
21            ('if (value != null && count >= 0) { return "airport"; }', 42, 385),
22            ('aopqnr mWw 6G9g 8B @#%& \'quoted\' "double" `grave`', 24, 455)]
23    report = {'font': {'path': str(path.relative_to(ROOT)), 'sha256': hashlib.sha256(path.read_bytes()).hexdigest()},
24              'weights': [200, 300, 400, 550, 700, 750, 800], 'em_pixels': [110, 48, 42, 24], 'endpoints': {}}
25    with TTFont(path) as variable:
26        for i, weight in enumerate(report['weights']):
27            font = instantiateVariableFont(variable, {'wght': weight, 'ital': 0}, inplace=False)
28            panel = Image.new('RGB', (2200, 520), '#fafafa')
29            panel.paste('#171c22', (0, 0), code_mask(font, rows, panel.size))
30            ImageDraw.Draw(panel).text((38, 20), f'iocgn Mono / wght {weight}', fill='#58616d', font=ImageFont.load_default(size=28))
31            sweep.paste(panel, (0, i * 520))
32            font.close()
33        for style, weight in [('ExtraLight', 200), ('Regular', 400), ('Bold', 700), ('ExtraBold', 800)]:
34            font = instantiateVariableFont(variable, {'wght': weight, 'ital': 0}, inplace=False)
35            directory = ROOT / 'build/native'
36            with TTFont(directory / f'iocgnMono-{style}.ttf') as static:
37                grid = [(''.join(chr(cp) for cp in range(start, min(start + 13, 127))), 256, 240 + i * 300)
38                        for i, start in enumerate(range(33, 127, 13))]
39                masks = [code_mask(f, grid, (1800, 2450)) for f in (static, font)]
40                difference = ImageChops.difference(*masks)
41                pixel_error = sum(ImageStat.Stat(difference).sum)
42                ink = sum(ImageStat.Stat(masks[0]).sum)
43                report['endpoints'][style] = {'absolute_raster_difference_over_ink': pixel_error / ink,
44                                              'em_pixels': 256}
45                assert pixel_error / ink < .025, (style, pixel_error / ink)
46                overlay = Image.merge('RGB', (masks[1], masks[0], ImageChops.lighter(*masks)))
47                overlay.save(output / f'endpoint-{style.lower()}.png')
48            font.close()
49        charset = Image.new('RGB', (6000, 1650), '#fafafa')
50        grid = [(''.join(chr(cp) for cp in range(start, min(start + 13, 127))), 160, 210 + i * 180)
51                for i, start in enumerate(range(33, 127, 13))]
52        for column, weight in enumerate((200, 400, 550, 700, 800)):
53            font = instantiateVariableFont(variable, {'wght': weight, 'ital': 0}, inplace=False)
54            panel = Image.new('RGB', (1200, 1650), '#fafafa')
55            panel.paste('#171c22', (0, 0), code_mask(font, grid, panel.size))
56            ImageDraw.Draw(panel).text((38, 20), f'wght {weight}', fill='#58616d', font=ImageFont.load_default(size=28))
57            charset.paste(panel, (column * 1200, 0))
58            panel.save(output / f'charset-{weight}.png')
59            font.close()
60        charset.save(output / 'charset.png')
61    sweep.save(output / 'weight-sweep.png')
62    template = ROOT / 'tools/variable-demo.html'
63    (output / 'index.html').write_bytes(template.read_bytes())
64    report['demo_sha256'] = hashlib.sha256(template.read_bytes()).hexdigest()
65    report['renderer_sha256'] = hashlib.sha256(Path(__file__).read_bytes()).hexdigest()
66    (output / 'render-manifest.json').write_text(json.dumps(report, indent=2) + '\n')
67    print(output / 'weight-sweep.png')
68    print('Endpoint raster differences:', report['endpoints'])
69
70
71if __name__ == '__main__':
72    main()