summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorRasmus Andersson <rasmus@notion.se>2018-09-04 02:06:04 +0300
committerRasmus Andersson <rasmus@notion.se>2018-09-04 02:06:04 +0300
commit4ab36d3e3bec37edc7e0eb7f9e20b0d14d37071c (patch)
tree3a96301ecb0ec566de7cfa779504a64f24d54e3c /misc
parent6785f6ea1cb049c2899ba8db602fe466c8b2e2a5 (diff)
downloadinter-4ab36d3e3bec37edc7e0eb7f9e20b0d14d37071c.tar.xz
update glyphinfo
Diffstat (limited to 'misc')
-rw-r--r--misc/tools/common.py23
-rwxr-xr-xmisc/tools/gen-glyphinfo.py223
2 files changed, 71 insertions, 175 deletions
diff --git a/misc/tools/common.py b/misc/tools/common.py
index c38ef817b..d53c8e755 100644
--- a/misc/tools/common.py
+++ b/misc/tools/common.py
@@ -3,6 +3,7 @@ from __future__ import print_function
import sys, os
from os.path import dirname, abspath, join as pjoin
import subprocess
+import time
# patch PYTHONPATH to include $BASEDIR/build/venv/python/site-packages
BASEDIR = abspath(pjoin(dirname(__file__), os.pardir, os.pardir))
@@ -34,5 +35,27 @@ def getVersion():
return _version
+_local_tz_offs = None
+def getLocalTimeZoneOffset(): # in seconds from UTC
+ # seriously ugly hack to get timezone offset in Python
+ global _local_tz_offs
+ if _local_tz_offs is None:
+ tzname = time.strftime("%Z", time.localtime())
+ s = time.strftime('%z', time.strptime(tzname, '%Z'))
+ i = 0
+ neg = False
+ if s[0] == '-':
+ neg = True
+ i = 1
+ elif s[0] == '+':
+ i = 1
+ h = int(s[i:i+2])
+ m = int(s[i+2:])
+ _local_tz_offs = ((h * 60) + m) * 60
+ if neg:
+ _local_tz_offs = -_local_tz_offs
+ return _local_tz_offs
+
+
# update environment to include $VENVDIR/bin
os.environ['PATH'] = os.path.join(VENVDIR, 'bin') + ':' + os.environ['PATH']
diff --git a/misc/tools/gen-glyphinfo.py b/misc/tools/gen-glyphinfo.py
index 4fdf73fae..9be36952e 100755
--- a/misc/tools/gen-glyphinfo.py
+++ b/misc/tools/gen-glyphinfo.py
@@ -4,129 +4,20 @@
# Grab http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
#
from __future__ import print_function
-import os, sys, json, re
+
+import os, sys
+from os.path import dirname, basename, abspath, relpath, join as pjoin
+sys.path.append(abspath(pjoin(dirname(__file__), 'tools')))
+from common import BASEDIR, getVersion, getLocalTimeZoneOffset
+
+import json, re
+import time
from argparse import ArgumentParser
-from robofab.objects.objectsRF import OpenFont
from collections import OrderedDict
-from unicode_util import parseUnicodeDataFile
from ConfigParser import RawConfigParser
-
-
-BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
-
-
-# Regex matching "default" glyph names, like "uni2043" and "u01C5"
-uniNameRe = re.compile(r'^u(?:ni)([0-9A-F]{4,8})$')
-
-
-def unicodeForDefaultGlyphName(glyphName):
- m = uniNameRe.match(glyphName)
- if m is not None:
- try:
- return int(m.group(1), 16)
- except:
- pass
- return None
-
-
-def loadAGL(filename): # -> { 2126: 'Omega', ... }
- m = {}
- with open(filename, 'r') as f:
- for line in f:
- # Omega;2126
- # dalethatafpatah;05D3 05B2 # higher-level combinations; ignored
- line = line.strip()
- if len(line) > 0 and line[0] != '#':
- name, uc = tuple([c.strip() for c in line.split(';')])
- if uc.find(' ') == -1:
- # it's a 1:1 mapping
- m[int(uc, 16)] = name
- return m
-
-
-def loadLocalNamesDB(fonts, agl, diacriticComps):
- uc2names = None # { 2126: ['Omega', ...], ...}
- allNames = OrderedDict() # {'Omega':True, ...}
-
- for font in fonts:
- _uc2names = font.getCharacterMapping() # { 2126: ['Omega', ...], ...}
- if uc2names is None:
- uc2names = _uc2names
- else:
- for uc, _names in _uc2names.iteritems():
- names = uc2names.setdefault(uc, [])
- for name in _names:
- if name not in names:
- names.append(name)
- for g in font:
- allNames.setdefault(g.name, True)
-
- # agl { 2126: 'Omega', ...} -> { 'Omega': [2126, ...], ...}
- aglName2Ucs = {}
- for uc, name in agl.iteritems():
- aglName2Ucs.setdefault(name, []).append(uc)
-
- for glyphName, comp in diacriticComps.iteritems():
- aglUCs = aglName2Ucs.get(glyphName)
- if aglUCs is None:
- uc = unicodeForDefaultGlyphName(glyphName)
- if uc is not None:
- glyphName2 = agl.get(uc)
- if glyphName2 is not None:
- glyphName = glyphName2
- names = uc2names.setdefault(uc, [])
- if glyphName not in names:
- names.append(glyphName)
- allNames.setdefault(glyphName, True)
- else:
- allNames.setdefault(glyphName, True)
- for uc in aglUCs:
- names = uc2names.get(uc, [])
- if glyphName not in names:
- names.append(glyphName)
- uc2names[uc] = names
-
- name2ucs = {} # { 'Omega': [2126, ...], ...}
- for uc, names in uc2names.iteritems():
- for name in names:
- name2ucs.setdefault(name, set()).add(uc)
-
- return uc2names, name2ucs, allNames
-
-
-def canonicalGlyphName(glyphName, uc2names):
- uc = unicodeForDefaultGlyphName(glyphName)
- if uc is not None:
- names = uc2names.get(uc)
- if names is not None and len(names) > 0:
- return names[0]
- return glyphName
-
-
-def parseGlyphComposition(composite):
- c = composite.split("=")
- d = c[1].split("/")
- glyphName = d[0]
- if len(d) == 1:
- offset = [0, 0]
- else:
- offset = [int(i) for i in d[1].split(",")]
- accentString = c[0]
- accents = accentString.split("+")
- baseName = accents.pop(0)
- accentNames = [i.split(":") for i in accents]
- return (glyphName, baseName, accentNames, offset)
-
-
-def loadGlyphCompositions(filename): # { glyphName => (baseName, accentNames, offset) }
- compositions = OrderedDict()
- with open(filename, 'r') as f:
- for line in f:
- line = line.strip()
- if len(line) > 0 and line[0] != '#':
- glyphName, baseName, accentNames, offset = parseGlyphComposition(line)
- compositions[glyphName] = (baseName, accentNames, offset)
- return compositions
+# from robofab.objects.objectsRF import OpenFont
+from unicode_util import parseUnicodeDataFile
+from defcon import Font
def rgbaToCSSColor(r=0, g=0, b=0, a=1):
@@ -134,7 +25,7 @@ def rgbaToCSSColor(r=0, g=0, b=0, a=1):
if a == 1:
return '#%02x%02x%02x' % (R,G,B)
else:
- return 'rgba(%d,%d,%d,%f)' % (R,G,B,a)
+ return 'rgba(%d,%d,%d,%g)' % (R,G,B,a)
def unicodeName(cp):
@@ -146,6 +37,14 @@ def unicodeName(cp):
return None
+# YYYY/MM/DD HH:mm:ss => YYYY-MM-DDTHH:mm:ssZ (local time -> UTC)
+def localDateTimeToUTCStr(localstr, pattern='%Y/%m/%d %H:%M:%S'):
+ t = time.strptime(localstr, pattern)
+ ts = time.mktime(t) - getLocalTimeZoneOffset()
+ return time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(ts))
+
+
+
def main():
argparser = ArgumentParser(
description='Generate info on name, unicodes and color mark for all glyphs')
@@ -158,18 +57,6 @@ def main():
'fontPaths', metavar='<ufofile>', type=str, nargs='+', help='UFO fonts to update')
args = argparser.parse_args()
- markLibKey = 'com.typemytype.robofont.mark'
-
- srcDir = os.path.join(BASEDIR, 'src')
-
- # load fontbuild config
- config = RawConfigParser(dict_type=OrderedDict)
- configFilename = os.path.join(srcDir, 'fontbuild.cfg')
- config.read(configFilename)
- deleteNames = set()
- for sectionName, value in config.items('glyphs'):
- if sectionName == 'delete':
- deleteNames = set(value.split())
fontPaths = []
for fontPath in args.fontPaths:
@@ -179,75 +66,61 @@ def main():
else:
fontPaths.append(fontPath)
- fonts = [OpenFont(fontPath) for fontPath in args.fontPaths]
-
- agl = loadAGL(os.path.join(srcDir, 'glyphlist.txt')) # { 2126: 'Omega', ... }
- diacriticComps = loadGlyphCompositions(os.path.join(srcDir, 'diacritics.txt'))
- uc2names, name2ucs, allNames = loadLocalNamesDB(fonts, agl, diacriticComps)
+ fonts = [Font(fontPath) for fontPath in args.fontPaths]
ucd = {}
if args.ucdFile:
ucd = parseUnicodeDataFile(args.ucdFile)
- glyphorder = OrderedDict()
- with open(os.path.join(os.path.dirname(args.fontPaths[0]), 'glyphorder.txt'), 'r') as f:
- for name in f.read().splitlines():
- if len(name) and name[0] != '#':
- glyphorder[name] = True
-
- for name in diacriticComps.iterkeys():
- glyphorder[name] = True
-
- glyphNames = glyphorder.keys()
+ glyphs = [] # contains final glyph data printed as JSON
visitedGlyphNames = set()
- glyphs = []
for font in fonts:
- for name, v in glyphorder.iteritems():
- if name in deleteNames:
- continue
+ glyphorder = font.lib['public.glyphOrder']
+ for name in glyphorder:
if name in visitedGlyphNames:
continue
- g = None
- ucs = []
- try:
- g = font[name]
- ucs = g.unicodes
- except:
- ucs = name2ucs.get(name)
- if ucs is None:
- continue
+ g = font[name]
+ # color
color = None
- if g is not None and markLibKey in g.lib:
- # TODO: translate from (r,g,b,a) to #RRGGBB (skip A)
- rgba = g.lib[markLibKey]
- if isinstance(rgba, list) or isinstance(rgba, tuple):
- color = rgbaToCSSColor(*rgba)
- elif name in diacriticComps:
- color = '<derived>'
+ if 'public.markColor' in g.lib:
+ rgba = [float(c.strip()) for c in g.lib['public.markColor'].strip().split(',')]
+ color = rgbaToCSSColor(*rgba)
+
+ # mtime
+ mtime = None
+ if 'com.schriftgestaltung.Glyphs.lastChange' in g.lib:
+ datetimestr = g.lib['com.schriftgestaltung.Glyphs.lastChange']
+ mtime = localDateTimeToUTCStr(datetimestr)
# name[, unicode[, unicodeName[, color]]]
+ glyph = None
+ ucs = g.unicodes
if len(ucs):
for uc in ucs:
ucName = unicodeName(ucd.get(uc))
-
if not ucName and uc >= 0xE000 and uc <= 0xF8FF:
ucName = '[private use %04X]' % uc
if color:
- glyph = [name, uc, ucName, color]
+ glyph = [name, uc, ucName, mtime, color]
+ elif mtime:
+ glyph = [name, uc, ucName, mtime]
elif ucName:
glyph = [name, uc, ucName]
else:
glyph = [name, uc]
-
- glyphs.append(glyph)
else:
- glyph = [name, None, None, color] if color else [name]
- glyphs.append(glyph)
-
+ if color:
+ glyph = [name, None, None, mtime, color]
+ elif mtime:
+ glyph = [name, None, None, mtime]
+ else:
+ glyph = [name]
+
+ glyphs.append(glyph)
visitedGlyphNames.add(name)
print('{"glyphs":[')