#!/usr/bin/python # -*- coding:utf8 -*- # Copyright 2014 Behdad Esfahbod # A slides file should populate the variable slides with # a list of tuples. Each tuple should have: # # - Slide content # - User data # - Canvas width # - Canvas height # # Slide content can be a string, a list of strings, # a function returning one of those, or a generator # yielding strings. The user data should be a dictionary or # None, and is both used to communicate options to the # renderer and to pass extra options to the theme functions. # # A function-based slide content will be passed a renderer object. # Renderer is an object similar to a cairo.Context and # pangocairo.CairoContext but has its own methods too. # The more useful of them here are put_text, put_image, and # set_allocation. See their pydocs. title_font="Cinzel" head_font="Julius Sans One Bold" body_font="Merriweather Sans Light" slides = [] def slide_add(f, data=None, width=960, height=600): if data is None: data = {} if "desc" not in data: data['desc'] = body_font slides.append ((f, data, width, height)) return f import pango, pangocairo, cairo, os, signal from pangopygments import highlight # We use slide data to tell the theme who's speaking. # That is, which side the bubble should point to. behdad = -1 whois = 0 def who(name): global whois whois = name # And convenience functions to add a slide. Can be # used as a function decorator, or called directly. def slide_who(f, who, data=None): if data: data = dict (data) else: data = {} data['who'] = who return slide_add (f, data) def slide(f, data=None): return slide_who (f, whois, data=data) def slide_heading(f, data=None): if data is None: data = {} if 'desc' not in data: data['desc'] = head_font if data and 'who' in data: return slide_who (f, data['who'], data=data) else: return slide_who (f, 0, data=data) def bullet_list_slide (title, items): def s (r): ts = ""+title+"\n" return ts + '\n'.join ("• " + item for item in items) s.__name__ = title data={'desc': body_font, 'align': pango.ALIGN_LEFT} slide (s, data) def image_slide (f, width=600, height=600, imgwidth=0, imgheight=0, xoffset=0, yoffset=0, data=None): def s (r): r.move_to (400+xoffset, 300+yoffset) r.put_image (f, width=imgwidth, height=imgheight) x = (800 - width) * .5 y = (600 - height) * .5 r.set_allocation (x, y, width, height) s.__name__ = f slide (s, data) return s def draw_image (r, f, width=600, height=600, imgwidth=0, imgheight=0, xoffset=0, yoffset=0, data=None): r.move_to (400+xoffset, 300+yoffset) r.put_image (f, width=imgwidth, height=imgheight) x = (800 - width) * .5 y = (600 - height) * .5 r.set_allocation (x, y, width, height) def source_slide(s, lang): s = highlight(s, lang) s = "" + s + "" slide_heading (s, data={'align': pango.ALIGN_LEFT}) def python_slide(s): source_slide(s, lang="py") def xml_slide(s): source_slide(s, lang="xml") def patch_slide(s): lines = s.split ("\n") new_lines = [] for s in lines: s = s.replace("&", "&").replace("<", "<") if not s: s = ' ' if s[0] == '-': s = "%s" % s elif s[0] == '+': s = "%s" % s elif s[0] != ' ': s = "%s" % s new_lines.append (s) s = '\n'.join (new_lines) s = "" + s + "" slide_heading (s, data={'align': pango.ALIGN_LEFT}) def commit_slide(s, who=None): lines = s.split ("\n") new_lines = [] for s in lines: s = s.replace("&", "&").replace("<", "<") if not s: s = ' ' if s[0] != ' ': s = "%s" % s new_lines.append (s) s = '\n'.join (new_lines) s = "" + s + "" if who: slide_heading (s, data={'align': pango.ALIGN_LEFT, 'who': who}) else: slide_heading (s, data={'align': pango.ALIGN_LEFT}) # # Slides start here # who (behdad) @slide def title_slide (r): r.move_to (400, 250) r.put_text ("FontTools\n"+ ""+ "reviving an Open Source project,\n"+ "rebuilding a thriving community"+ "", valign=0, halign=0, desc=title_font+" 100") r.move_to (400, 550) r.put_text ("""Behdad Esfahbod""", desc=body_font+" 20", halign=0, valign=-1) bullet_list_slide("History", [ "Started in 1999ish", "by Just van Rossum", "of LettError fame", "Slowed down by 2004", "I picked it up last year"]) bullet_list_slide("What is it?", [ "Two things: TTX and fontTools", "TTX converts fonts to XML and back", "fontTools is a Python library", "Font engineer's calculator", "Closely reflecting OpenType tables", "Minimum abstractions"]) slide_heading("TTX") xml_slide(""" ... ... """) xml_slide(""" ... ... """) xml_slide(""" """) xml_slide(""" ... """) xml_slide(""" Julius Sans One Regular """) slide_heading("fontTools") bullet_list_slide("from fontTools import", [ "afmLib", "cffLib", "fondLib", "nfntLib", "t1Lib", "ttLib", ]) python_slide(open("snippets/unencoded.py").read()) python_slide(""" set(['A.salt', 'B.salt', 'E.salt', 'E_x', 'F_i', 'N.salt', 'NULL', 'T_h', 'T_i', 'a.end', ... 'y_z']) """) bullet_list_slide("Framework", [ "Compiler / decompiler", "XML serialization", "Optimizer", "Library", "A tool to build products with", "Not an end product", ]) bullet_list_slide("Philosophy", [ "Minimal abstraction", "Hide byte layout, redundancy, etc", "Platform to build on", ]) bullet_list_slide("Why?", [ "Free Software", "Python (2.7+ & 3.x)", "Portable", "No dependencies", "Non-destructive", "Batch-friendly", ]) bullet_list_slide("What for?", [ "Figuring out what's inside a font", "Diff'ing font versions", "Final steps of producing fonts", "Hotfixing existing fonts", "Reporting and analysis over many fonts", "Server-side reporting and manipulation", "Readable VCS-friendly font source code", "Subsetting and merging fonts", ]) bullet_list_slide("Hotfixing", [ "XML and back", "Python recipes", "Interactive Python", ]) python_slide(open("snippets/drop_glyphnames.py").read()) python_slide(open("snippets/rename_glyphs.py").read()) bullet_list_slide("New work", [ "Bitmap tables, color tables, misc tables", "WOFF1 read and write", "More stable XML format", "More optimized font files", "Bug fixes; many of them", "Major speed-up", "New tools", ]) bullet_list_slide("Tools", [ "pyftsubset", "pyftmerge", "pyftinspect", ]) bullet_list_slide("pyftsubset", [ "OpenType font subsetter & optimizer", "TrueType and CFF flavored", "SFNT and WOFF1", "Full OpenType Layout support", "File-size optimizations", "Designed for webfont productions", "Used for sub-family instantiation", ]) source_slide(open("snippets/subsetting.txt").read(), "text") bullet_list_slide("pyftmerge", [ "Font merging tool", "Very early prototype", "Fonts having same format, upem", "TrueType-flavored only", "Retains hinting from one font", "Handles conflicting characters", "Designed for Noto", "Used for merging Latin and non-Latin", ]) source_slide(open("snippets/merging.txt").read(), "text") # 1. Feel free to mention in your talk Yannis Haralambous' book "Fonts & Encodings" [1], simply because it can be seen as a "user manual for TTX". It talks extensively about the various SFNT tables, and illustrates them using TTX XML structures. So, while fontTools itself has very lacking documentation*, the book is actually a great companion. When I read the book and I look at the .ttx XML representation of a font, I have good chances to actually understand how it all works. slide_heading("FontTools") bullet_list_slide("Strengths", [ "Supports wide array of tables", "Low-level, non-destructive", "Python", "Self-documenting", "Optimized output", "Extensible", "Supports all color tables", ]) bullet_list_slide("Weaknesses", [ "Supports wide array of tables", "Low-level, non-destructive", "Python", "Undocumented", "Always optimizes output", "Not well-extensible", "Supports many legacy tables", ]) bullet_list_slide("Users", [ "Google Fonts; misc foundries", "Font Bakery, AFDKO, etc", "Adam Twardoch; others", "...", ]) bullet_list_slide("Community", [ "https://github.com/behdad/fonttools/", "https://groups.google.com/forum/#!forum/fonttools", "http://sourceforge.net/projects/fonttools/", ]) bullet_list_slide("Future work", [ "More font optimization", "Better input: .fea / UFO", "ttx2ufo", "Lint tool", "TrueType / CFF conversion", "Subsetting more tables", "Better merging", ]) bullet_list_slide("Future work: optimization", [ "Optimal packing: glyf flags / PUSH / etc", "CFF outline operation specializer", "CFF subroutinizer", "TrueType outline optimizer? (fontcrunch)", "TrueType bytecode analysis", "UPEM reduction", ]) slide("Q?", data={"desc":title_font}) python_slide('') python_slide(open("snippets/drop_glyphnames_cff.py").read()) xml_slide(open("snippets/tofu.ttx").read()) if __name__ == "__main__": import slippy import fonttools_theme slippy.main (slides, fonttools_theme, args=['--geometry', '1920x1200'])