summaryrefslogtreecommitdiff
path: root/misc/fontbuild
diff options
context:
space:
mode:
authorRasmus Andersson <rasmus@notion.se>2018-11-23 23:52:50 +0300
committerRasmus Andersson <rasmus@notion.se>2018-11-23 23:52:50 +0300
commita8fc89d01f4b281cd4ebd30532a6b61fa51bc913 (patch)
tree22abcca83a8520c36e13b5a44dc0890b1e49c4c8 /misc/fontbuild
parent783f38a7000f208abf4f7b78443b82dec2d57b94 (diff)
downloadinter-a8fc89d01f4b281cd4ebd30532a6b61fa51bc913.tar.xz
fontbuild: adds support for post-processing directives on a per-glyph basis. Add "!post:DIRECTIVE" in glyph notes. Only supported directive is "removeoverlaps"
Diffstat (limited to 'misc/fontbuild')
-rwxr-xr-xmisc/fontbuild64
1 files changed, 50 insertions, 14 deletions
diff --git a/misc/fontbuild b/misc/fontbuild
index d272a7aec..ebbcd4329 100755
--- a/misc/fontbuild
+++ b/misc/fontbuild
@@ -25,10 +25,11 @@ from fontTools.pens.reverseContourPen import ReverseContourPen
from glyphsLib.interpolation import apply_instance_data
from mutatorMath.ufo.document import DesignSpaceDocumentReader
from multiprocessing import Process, Queue
-# from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter
+from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter
log = logging.getLogger(__name__)
stripItalic_re = re.compile(r'(?:^|\b)italic(?:\b|$)', re.I | re.U)
+findPost_re = re.compile(r'\!post:([^ ]+)', re.I | re.U)
def stripItalic(name):
@@ -77,6 +78,26 @@ def composedGlyphIsNonTrivial(g, yAxisIsNonTrivial=False):
return False
+knownDirectives = set([
+ 'removeoverlap',
+])
+
+
+def findGlyphDirectives(g): # -> set<string> | None
+ directives = set()
+ if g.note and len(g.note) > 0:
+ for directive in findPost_re.findall(g.note):
+ directive = directive.lower()
+ if directive in knownDirectives:
+ directives.add(directive)
+ else:
+ print(
+ 'unknown glyph directive !post:%s in glyph %s' % (directive, g.name),
+ file=sys.stderr
+ )
+ return directives
+
+
class VarFontProject(FontProject):
def decompose_glyphs(self, ufos, glyph_filter=lambda g: True):
"""Move components of UFOs' glyphs to their outlines."""
@@ -100,29 +121,42 @@ class VarFontProject(FontProject):
# the contour direction of the component
xx, xy, yx, yy = transformation[:4]
if xx*yy - xy*yx < 0:
- pen = ReverseContourPen(pen)
+ pen = ReverseContourPen(pen)
component.draw(pen)
def build_interpolatable_ttfs(self, ufos, **kwargs):
"""Build OpenType binaries with interpolatable TrueType outlines."""
# We decompose any glyph with two or more components to make sure
# that fontTools varLib is able to produce properly-slanting interpolation.
-
+
decomposeGlyphs = set()
+ removeOverlapsGlyphs = set()
+
for ufo in ufos:
updateFontVersion(ufo)
isItalic = ufo.info.italicAngle != 0
- for glyph in ufo:
- if glyph.components and composedGlyphIsNonTrivial(glyph, yAxisIsNonTrivial=isItalic):
- decomposeGlyphs.add(glyph.name)
+ ufoname = basename(ufo.path)
+ for g in ufo:
+ directives = findGlyphDirectives(g)
+ if g.components and composedGlyphIsNonTrivial(g, yAxisIsNonTrivial=isItalic):
+ decomposeGlyphs.add(g.name)
+ if 'removeoverlap' in directives:
+ if g.components and len(g.components) > 0:
+ decomposeGlyphs.add(g.name)
+ removeOverlapsGlyphs.add(g)
self.decompose_glyphs(ufos, lambda g: g.name in decomposeGlyphs)
- # for ufo in ufos:
- # filter = RemoveOverlapsFilter(backend='pathops')
- # filter.start()
- # for g in ufo:
- # filter.filter(g)
+ if len(removeOverlapsGlyphs) > 0:
+ rmoverlapFilter = RemoveOverlapsFilter(backend='pathops')
+ rmoverlapFilter.start()
+ for g in removeOverlapsGlyphs:
+ log.info(
+ 'Removing overlaps in glyph "%s" of %s',
+ g.name,
+ basename(g.getParent().path)
+ )
+ rmoverlapFilter.filter(g)
self.save_otfs(ufos, ttf=True, interpolatable=True, **kwargs)
@@ -268,6 +302,7 @@ class Main(object):
# parse CLI arguments
args = argparser.parse_args(argv[1:i])
+ logFormat = '%(funcName)s: %(message)s'
if args.quiet:
self.quiet = True
if args.debug:
@@ -275,13 +310,14 @@ class Main(object):
if args.verbose:
fatal("--quiet and --verbose are mutually exclusive arguments")
elif args.debug:
- logging.basicConfig(level=logging.DEBUG)
+ logging.basicConfig(level=logging.DEBUG, format=logFormat)
self.logLevelName = 'DEBUG'
elif args.verbose:
- logging.basicConfig(level=logging.INFO)
+ logging.basicConfig(level=logging.INFO, format=logFormat)
self.logLevelName = 'INFO'
else:
- logging.basicConfig(level=logging.WARNING)
+ logFormat = '%(message)s'
+ logging.basicConfig(level=logging.WARNING, format=logFormat)
self.logLevelName = 'WARNING'
if args.chdir: