1
0
mirror of https://github.com/google/fonts.git synced 2024-12-26 02:04:42 +03:00

Open source add_font and what_subsets.

This commit is contained in:
Rod Sheeter 2016-01-07 08:16:37 -08:00
parent 697f9096d4
commit cbeaf9a685
4 changed files with 290 additions and 13 deletions

132
tools/add_font.py Normal file
View File

@ -0,0 +1,132 @@
import errno
import glob
import os
import re
import sys
import time
import fonts_public_pb2 as fonts_pb2
from google.protobuf import text_format
from google.apputils import app
from util import google_fonts as fonts
def _FileFamilyStyleWeights(fontdir):
"""Extracts file, family, style, weight 4-tuples for each font in dir.
Args:
fontdir: Directory that supposedly contains font files for a family.
Returns:
List of fonts.FileFamilyStyleWeightTuple ordered by weight, style
(normal first).
Raises:
OSError: If the font directory doesn't exist (errno.ENOTDIR) or has no font
files (errno.ENOENT) in it.
RuntimeError: If the font directory appears to contain files from multiple
families.
"""
if not os.path.isdir(fontdir):
raise OSError(errno.ENOTDIR, 'No such directory', fontdir)
files = glob.glob(os.path.join(fontdir, '*.ttf'))
if not files:
raise OSError(errno.ENOENT, 'no font files found')
result = [fonts.FileFamilyStyleWeight(f) for f in files]
def _Cmp(r1, r2):
return cmp(r1.weight, r2.weight) or -cmp(r1.style, r2.style)
result = sorted(result, _Cmp)
family_names = {i.family for i in result}
if len(family_names) > 1:
raise RuntimeError('Ambiguous family name; possibilities: %s'
% family_names)
return result
def _MakeMetadata(fontdir):
"""Builds a dictionary matching a METADATA.pb file.
Args:
fontdir: Directory containing font files for which we want metadata.
Returns:
OrderedDict of a complete METADATA.pb structure.
"""
file_family_style_weights = _FileFamilyStyleWeights(fontdir)
first_file = file_family_style_weights[0].file
subsets = ['menu'] + [s[0] for s in fonts.SubsetsInFont(first_file, 50)]
font_license = fonts.LicenseFromPath(fontdir)
metadata = fonts_pb2.FamilyProto()
metadata.name = file_family_style_weights[0].family
metadata.designer = 'Unknown'
metadata.category = 'SANS_SERIF'
metadata.license = font_license
for subset in subsets:
metadata.subsets.append(subset)
metadata.date_added = time.strftime('%Y-%m-%d')
for (fontfile, family, style, weight) in file_family_style_weights:
filename = os.path.basename(fontfile)
font_psname = fonts.ExtractName(fontfile, fonts.NAME_PSNAME,
os.path.splitext(filename)[0])
font_copyright = fonts.ExtractName(fontfile, fonts.NAME_COPYRIGHT, '???.')
font_metadata = metadata.fonts.add()
font_metadata.name = family
font_metadata.style = style
font_metadata.weight = weight
font_metadata.filename = filename
font_metadata.post_script_name = font_psname
font_metadata.full_name = os.path.splitext(filename)[0].replace('-', ' ')
return metadata
def _WriteTextFile(filename, text):
"""Write text to file.
Nop if file exists with that exact content. This allows running against files
that are in Piper and not marked for editing; you will get an error only if
something changed.
Args:
filename: The file to write.
text: The content to write to the file.
"""
if os.path.isfile(filename):
with open(filename, 'r') as f:
current = f.read()
if current == text:
print 'No change to %s' % filename
return
with open(filename, 'w') as f:
f.write(text)
print 'Wrote %s' % filename
def main(argv):
if len(argv) != 2:
sys.exit('One argument, a directory containing a font family')
fontdir = argv[1]
metadata = _MakeMetadata(fontdir)
text_proto = text_format.MessageToString(metadata)
_WriteTextFile(os.path.join(fontdir, 'DESCRIPTION.en_us.html'), 'N/A')
_WriteTextFile(os.path.join(fontdir, 'METADATA.pb'), text_proto)
if __name__ == '__main__':
app.run()

View File

@ -12,11 +12,10 @@ import sys
from fontTools import ttLib
import fonts_public_pb2 as fonts_pb2
from google.protobuf import text_format
import gflags as flags
from google.apputils import resources
from util import py_subsets
FLAGS = flags.FLAGS
flags.DEFINE_string('nam_dir', 'encodings/', 'nam file dir')
@ -71,6 +70,13 @@ _FS_SELECTION_BITS = [
]
# license_dir => license name mappings
_KNOWN_LICENSE_DIRS = {
'apache': 'APACHE2',
'ofl': 'OFL',
'ufl': 'UFL',
}
FileFamilyStyleWeightTuple = collections.namedtuple(
'FileFamilyStyleWeightTuple', ['file', 'family', 'style', 'weight'])
@ -145,17 +151,8 @@ def RegularWeight(metadata):
def ListSubsets():
"""Returns a list of all subset names, in lowercase, except */all and menu."""
subsets = []
with resources.GetResourceAsFile(_SUBSET_RESOURCE_PATH) as f:
for l in f:
match = _SUBSET_PATTERN.search(l)
if match and match.group(1) not in ('ALL', 'MENU'):
subsets.append(match.group(2))
return subsets
"""Returns a list of all subset names, in lowercase."""
return py_subsets.SUBSETS
def Metadata(file_or_dir):
@ -499,3 +496,28 @@ def FsSelectionFlags(fs_selection):
return names
def _EntryForEndOfPath(path, answer_map):
segments = [s.lower() for s in path.split(os.sep)]
answers = [answer_map[s] for s in segments
if s in answer_map]
if len(answers) != 1:
raise ValueError('Found %d possible matches: %s' % (
len(answers), answers))
return answers[0]
def LicenseFromPath(path):
"""Try to figure out the license for a given path.
Splits path and looks for known license dirs in segments.
Args:
path: A filesystem path, hopefully including a license dir.
Returns:
The name of the license, eg OFL, UFL, etc.
Raises:
ValueError: if 0 or >1 licenses match path.
"""
return _EntryForEndOfPath(path, _KNOWN_LICENSE_DIRS)

98
tools/util/py_subsets.py Executable file
View File

@ -0,0 +1,98 @@
SUBSETS = [
"arabic",
"armenian",
"avestan",
"balinese",
"bamum",
"batak",
"bengali",
"brahmi",
"buginese",
"buhid",
"myanmar",
"canadian-aboriginal",
"carian",
"cham",
"chakma",
"cherokee",
"chinese-simplified",
"chinese-traditional",
"coptic",
"cuneiform",
"cypriot",
"cyrillic",
"cyrillic-ext",
"deseret",
"egyptian-hieroglyphs",
"ethiopic",
"georgian",
"gothic",
"greek",
"greek-ext",
"gujarati",
"gurmukhi",
"hanunoo",
"hebrew",
"imperial-aramaic",
"inscriptional-pahlavi",
"inscriptional-parthian",
"devanagari",
"japanese",
"javanese",
"kaithi",
"kannada",
"kayah-li",
"kharoshthi",
"khmer",
"korean",
"lao",
"latin",
"latin-ext",
"lepcha",
"limbu",
"linear-b",
"lisu",
"lycian",
"lydian",
"malayalam",
"mandaic",
"meetei-mayek",
"mongolian",
"new-tai-lue",
"ol-chiki",
"old-italic",
"old-persian",
"old-south-arabian",
"old-turkic",
"ogham",
"oriya",
"osmanya",
"phags-pa",
"runic",
"samaritan",
"phoenician",
"rejang",
"saurashtra",
"shavian",
"sinhala",
"sundanese",
"syloti-nagri",
"syriac-eastern",
"syriac-estrangela",
"syriac-western",
"tagalog",
"tagbanwa",
"tai-le",
"tai-tham",
"tai-viet",
"tamil",
"telugu",
"thaana",
"thai",
"tibetan",
"tifinagh",
"vai",
"ugaritic",
"vietnamese",
"yi"
]

25
tools/what_subsets.py Normal file
View File

@ -0,0 +1,25 @@
import os
from google.apputils import app
import gflags as flags
from util import google_fonts as fonts
FLAGS = flags.FLAGS
flags.DEFINE_integer('min_pct', 0,
'What percentage of subset codepoints have to be supported'
' to print.')
def main(argv):
for arg in argv[1:]:
for (subset, available, total) in fonts.SubsetsInFont(arg, FLAGS.min_pct):
print '%s %s %d/%d' % (os.path.basename(arg), subset, available, total)
if __name__ == '__main__':
app.run()