| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 | #!/usr/bin/env python# -*- coding: utf-8 -*-#  ------------------------------------------------------------------------------#  font-tables.py#  Copyright 2015 Christopher Simpkins#  MIT license#  ------------------------------------------------------------------------------import sysimport osimport os.pathimport hashlibfrom fontTools import ttLib# TODO: expand Python objects within the table values# TODO: modify TTFA table read to create YAML format from the stringsdef main(fontpaths):    """The main function creates a YAML formatted report on the OpenType tables in one    or more fonts included in the fontpaths function parameter.    :param fontpaths: """    # create a report directory, gracefully fail if it already exists    if not os.path.isdir("otreports"):        os.mkdir("otreports")    # iterate through fonts requested in the command    for fontpath in fontpaths:        if os.path.isfile(fontpath):            # create a fonttools TTFont object using the fontpath            tt = ttLib.TTFont(fontpath)            print("Processing " + fontpath + "...")            # define the outfile path            basename = os.path.basename(fontpath)            basefilename = basename + "-TABLES.yaml"            outfilepath = os.path.join("otreports", basefilename)            # read the font data and create a SHA1 hash digest for the report            fontdata = read_bin(fontpath)            hash_digest = hashlib.sha1(fontdata).hexdigest()            # report strings for file name and SHA1 digest            report_header_string = "FILE: " + fontpath + "\n"            report_header_string += "SHA1: " + hash_digest + "\n\n"            # open outfile write stream, create file, write name + SHA1 header            with open(outfilepath, "w") as writer:                writer.write(report_header_string)            # iterate through the OpenType tables, write table fields in a newline delimited format with YAML syntax            for table in tt.keys():                table_dict = tt[table].__dict__                if len(table_dict) > 0:                    table_string = yaml_formatter(table, table_dict)                    with open(outfilepath, 'a') as appender:                                appender.write(table_string)                    print("[✓] " + table)                else:                    print("[E] " + table)  # indicate missing table data in standard output, do not write to YAML file            print(fontpath + " table report is available in " + outfilepath + "\n")        else:  # not a valid filepath            sys.stderr.write("Error: '" + fontpath + "' was not found. Please check the filepath.\n\n")def yaml_formatter(table_name, table_dict):    """Creates a YAML formatted string for OpenType table font reports"""    # define the list of tables that require table-specific processing    special_table_list = ['name', 'OS/2', 'TTFA']    if table_name in special_table_list:        if table_name == "name":            return name_yaml_formatter(table_dict)        elif table_name == "OS/2":            return os2_yaml_formatter(table_dict)        elif table_name == "TTFA":            return ttfa_yaml_formatter(table_dict)    else:        table_string = table_name.strip() + ": {\n"        for field in table_dict.keys():            table_string = table_string + (" " * 4) + field + ": " + str(table_dict[field]) + ',\n'        table_string += "}\n\n"        return table_stringdef name_yaml_formatter(table_dict):    """Formats the YAML table string for OpenType name tables"""    table_string = "name: {\n"    namerecord_list = table_dict['names']    for record in namerecord_list:        if record.__dict__['langID'] == 0:            record_name = str(record.__dict__['nameID'])        else:            record_name = str(record.__dict__['nameID']) + "u"        record_field = (" " * 4) + "nameID" + record_name        table_string = table_string + record_field + ": " + str(record.__dict__) + ",\n"    table_string = table_string + "}\n\n"    return table_stringdef os2_yaml_formatter(table_dict):    """Formats the YAML table string for OpenType OS/2 tables"""    table_string = "OS/2: {\n"    for field in table_dict.keys():        if field == "panose":            table_string = table_string + (" "*4) + field + ": {\n"            panose_string = ""            panose_dict = table_dict['panose'].__dict__            for panose_field in panose_dict.keys():                panose_string = panose_string + (" " * 8) + panose_field[1:] + ": " + str(panose_dict[panose_field]) + ",\n"            table_string = table_string + panose_string + (" " * 4) + "}\n"        else:            table_string = table_string + (" "*4) + field + ": " + str(table_dict[field]) + ',\n'    table_string = table_string + "}\n\n"    return table_stringdef ttfa_yaml_formatter(table_dict):    """Formats the YAML table string for the ttfautohint TTFA table"""    data_string = table_dict['data'].strip()    data_list = data_string.split('\n')  # split on newlines in the string    table_string = "TTFA: {\n"    for definition_string in data_list:        definition_list = definition_string.split("=")        field = definition_list[0].strip()        if len(definition_list) > 1:            value = definition_list[1].strip()        else:            value = "''"        table_string = table_string + (" " * 4) + field + ": " + value + ",\n"    table_string = table_string + "}\n\n"    return table_stringdef read_bin(filepath):    """read_bin function reads filepath parameter as binary data and returns raw binary to calling code"""    try:        with open(filepath, 'rb') as bin_reader:            data = bin_reader.read()            return data    except Exception as e:        sys.stderr.write("Error: Unable to read file " + filepath + ". " + str(e))if __name__ == '__main__':    main(sys.argv[1:])
 |