def getGlyphInfos(self): result = [] # glyphIndexToNameMap = {} glyphToCharacterMap = self.getGlyphIndexToCharacterMap() if self.ftFont.has_glyph_names: for glyphIndex in self.getGlyphIndices(): glyphNameBuffer = ' '*256 error = freetype.FT_Get_Glyph_Name(self.ftFont._FT_Face, glyphIndex, glyphNameBuffer, len(glyphNameBuffer) - 1) if error: raise freetype.FT_Exception(error) glyphInfo = TFSMap() glyphInfo.glyphIndex = glyphIndex glyphInfo.glyphName = glyphNameBuffer.strip()[:-1] # print 'glyphName', glyphIndex, glyphName, len(glyphName) glyphInfo.characterCode = None if glyphIndex in glyphToCharacterMap: glyphInfo.characterCode = glyphToCharacterMap[glyphIndex] result.append(glyphInfo) else: for glyphIndex, characterCode in glyphToCharacterMap.items(): glyphInfo = TFSMap() glyphInfo.glyphIndex = glyphIndex glyphInfo.glyphName = getUnicodeCharacterName(characterCode) glyphInfo.characterCode = characterCode # glyphInfoMap[glyphIndex] = glyphInfo result.append(glyphInfo) return result
def getCommandLineSettings(self, *replacementValues): parser = self.createParser() if replacementValues: args = parser.parse_args(replacementValues) else: args = parser.parse_args() # print 'args', args if self.target is None: self.target = TFSMap() ''' Copy attributes ''' if self.dumpCommandLineSettings(): print() for attr in sorted(dir(args)): if attr.startswith('_'): continue if self.dumpCommandLineSettings(): print('arg', attr, getattr(args, attr)) setattr(self.target, attr, getattr(args, attr)) if self.dumpCommandLineSettings(): print()
def do_kern_for_pairs(dir_path, fontfilename, weights_str, kernlistdir): x = 0 # _dir = dir_path + '/' # weights = weights_str.split(',') # get_kern_pair_file_to_tupple(fontfilename, weights, kernlistdir) # for w in weights: # print(_dir + fontfilename + "_" + w + ".ufo") # in_fnt = _dir + fontfilename + "_" + w + "_krn.ufo" out_fnt = _dir + fontfilename + "_" + w + "_krn_fix.ufo" # pseudo_argv = ('--ufo-src-path', in_fnt, '--ufo-dst-path', out_fnt, '--min-distance-ems', '0.04', '--max-distance-ems', '0.05', '--max-x-extrema-overlap-ems', '0.1', '--intrusion-tolerance-ems', '0.02', '--precision-ems', '0.005', '--glyph-pairs-to-kern') autokernArgs = TFSMap() AutokernSettings(autokernArgs).getCommandLineSettings(*(pseudo_argv + pairlist[w])) autokern = Autokern(autokernArgs) autokern.process() # x = x + 1 # print('Completed:' + w + ' ' + str(x) + '/' + str(len(weights)) + '\n' + ' Produced Kerned UFO:' + out_fnt) # print('Replace the kern.plist at your leasure')
def do_kern_for_pairs(dir_path, fontfilename, weights_str): x = 0 # _dir = dir_path + '/' # weights = weights_str.split(',') # # for w in weights: # print(_dir + fontfilename + "_" + w + ".ufo") # in_fnt = _dir + fontfilename + "_" + w + ".ufo" out_fnt = _dir + fontfilename + "_" + w + "_krn.ufo" # pseudo_argv = ( '--ufo-src-path', in_fnt, '--ufo-dst-path', out_fnt, '--min-distance-ems', '0.08', '--max-distance-ems', '0.10', '--max-x-extrema-overlap-ems', '0.10', '--intrusion-tolerance-ems', '0.02', '--precision-ems', '0.005', #'--log-path', #'/media/root/Malysh1/winshm/advent_repo/Advent/scripts/kerning_scripts/kern_log/log', #'--log-basic-pairs', #'--write-kerning-pair-logs' ) print('pseudo_argv', ' '.join([str(arg) for arg in pseudo_argv])) autokernArgs = TFSMap() AutokernSettings(autokernArgs).getCommandLineSettings(*pseudo_argv) autokern = Autokern(autokernArgs) autokern.process() # x = x + 1 # print('Completed:' + w + ' ' + str(x) + '/' + str(len(weights)) + '\n' + ' Produced Kerned UFO:' + out_fnt) # print('Replace the kern.plist at your leasure')
# pseudo_argv = ('--ufo-src-path', os.path.join(pardir,'advent_pro','advent_pro_thn.ufo'), '--ufo-dst-path', os.path.join(pardir,'advent_pro','advent_pro_thn_flat_kern.ufo'), '--min-distance-ems', '0.05', '--max-distance-ems', '0.1', '--max-x-extrema-overlap-ems', '0.1', '--intrusion-tolerance-ems', '0.4', '--precision-ems', '0.02', #'--log-path', #os.path.join(pardir,'logs','log'), #'--log-basic-pairs', #'--write-kerning-pair-logs', ) print ('pseudo_argv', ' '.join([str(arg) for arg in pseudo_argv])) autokernArgs = TFSMap() AutokernSettings(autokernArgs).getCommandLineSettings(*pseudo_argv) autokern = Autokern(autokernArgs) autokern.process() print ('complete.')
def dumpMetricsMap(self, kerningPairMap, htmlFilename): print print 'fonts scanned:', len(self.processedPostscriptNames) print 'fonts processed:', len(self.nonEmptyPostscriptNames) print 'glyph pairs observed:', len(kerningPairMap) maxGlyphPairCount = reduce(max, kerningPairMap.values()) print 'Highest glyph pair frequency:', maxGlyphPairCount glyphs = [] for ( glyph0, glyph1, ), count in kerningPairMap.iteritems(): glyph = TFSMap() glyph.glyph0 = glyph0 glyph.glyph1 = glyph1 glyph.count = count glyphs.append(glyph) def glyphCountSort(glyph0, glyph1): # Negate; we want reverse order for count. result = -cmp(glyph0.count, glyph1.count) if result != 0: return result result = cmp(glyph0.glyph0, glyph1.glyph0) if result != 0: return result result = cmp(glyph0.glyph1, glyph1.glyph1) if result != 0: return result return 0 # return cmp(glyph0.codePoint, glyph1.codePoint) glyphs.sort(glyphCountSort) print 'Most common glyph:', glyphs[0] print 'Least common glyph:', glyphs[-1] locale.setlocale(locale.LC_ALL, 'en_US') pres = [] for glyph in glyphs[:5000]: # for glyph in glyphs[:1000]: # pre = {} pre = { # 'glyphHex': hex(glyph.codePoint), 'glyphHex0': '%04X' % glyph.glyph0, 'glyphHex1': '%04X' % glyph.glyph1, # 'glyphName0': getUnicodeLongName(glyph.glyph0, # ignoreUnknown=True, # skipValidation=True), # 'glyphName1': getUnicodeLongName(glyph.glyph1, # ignoreUnknown=True, # skipValidation=True), 'glyphName0': getUnicodeCharacterName(glyph.glyph0, ignoreUnknown=True), 'glyphName1': getUnicodeCharacterName(glyph.glyph1, ignoreUnknown=True), 'glyphCount': locale.format("%d", glyph.count, grouping=True), 'glyphPercent': '%0.2f%%' % (100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames))), # 'glyphColor': '%06X' % glyphColor, } # pre['value'] = '%s %s: %d (%0.2f%%)' % ( hex(glyph.codePoint), # getUnicodeLongName(glyph.codePoint, # ignoreUnknown=True, # skipValidation=True), # glyph.count, # glyph.count / float(len(self.nonEmptyPostscriptNames)), # ) # print 'pre', pre pres.append(pre) self.writeMustacheLog( 'kia_pre_template.txt', htmlFilename, # 'most_common_kerning_pairs.html', mustacheVars={ 'pres': pres, # 'headerPres': headerPres, 'pageTitle': '1,000 Most Common Kerning Pairs', 'headerTitle': '1,000 Most Common Kerning Pairs', # 'headerTitle': 'Kerning Pairs Implementation Statistics', 'statsTitle': 'Statistics', 'stats': ( { 'key': 'Total Fonts', 'value': locale.format("%d", len(self.processedPostscriptNames), grouping=True), }, { 'key': 'Fonts With Valid Kerning Table', 'value': locale.format("%d", len(self.nonEmptyPostscriptNames), grouping=True), }, { 'key': 'Kerning Pairs Observed', 'value': locale.format("%d", len(kerningPairMap), grouping=True), }, ), } # replaceMap = {'<!-- SVG Graph Placeholder -->': tableSvg, # } )
def dumpMetrics(self): print print 'fonts scanned:', len(self.processedPostscriptNames) print 'fonts processed:', len(self.nonEmptyPostscriptNames) print 'glyph pairs observed:', len(self.kerningPairCountMap) maxGlyphPairCount = reduce(max, self.kerningPairCountMap.values()) print 'Highest glyph pair frequency:', maxGlyphPairCount # self.dumpMetricsMap(self.kerningPairCountMap, 'most_common_kerning_pairs.html') # self.dumpMetricsMap(self.kerningPairAbsEmsMap, 'most_common_kerning_pairs_ems.html') # kerningPairAverageMap = {} # for key in self.kerningPairCountMap: # kerningPairAverageMap[key] = self.kerningPairAbsEmsMap[key] / self.kerningPairCountMap[key] # self.dumpMetricsMap(kerningPairAverageMap, 'most_common_kerning_pairs_avg.html') countGlyphs = [] avgGlyphs = [] for key in self.kerningPairCountMap: glyph0, glyph1 = key glyph = TFSMap() glyph.glyph0 = glyph0 glyph.glyph1 = glyph1 glyph.absEmsTotal = self.kerningPairAbsEmsMap[key] glyph.count = self.kerningPairCountMap[key] glyph.frequencyPct = 100.0 * glyph.count / float( len(self.nonEmptyPostscriptNames)) glyph.absEmsRawAverage = self.kerningPairAbsEmsMap[key] / float( len(self.nonEmptyPostscriptNames)) glyph.absEmsWeightedAverage = self.kerningPairAbsEmsMap[ key] / float(self.kerningPairCountMap[key]) glyphHex0 = '%04X' % glyph.glyph0 glyphHex1 = '%04X' % glyph.glyph1 def getGlyphName(codePoint): result = getUnicodeCharacterName(codePoint, ignoreUnknown=True, skipValidation=True) if result is None: return 'Unknown' result = result.replace('<', '').replace('>', '') return result glyph.label = '0x%s &#x%s %s vs. 0x%s &#x%s %s' % ( glyphHex0, glyphHex0, getGlyphName(glyph.glyph0), glyphHex1, glyphHex1, getGlyphName(glyph.glyph1), ) # 'glyphCount': locale.format("%d", glyph.count, grouping=True), # 'glyphPercent': '%0.2f%%' % (100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames))), if glyph.frequencyPct >= 10.0: countGlyph = TFSMap(glyph) countGlyph.sortValue = glyph.count countGlyph.displayValue = glyph.count countGlyph.displayValue = '%0.0f%%' % (glyph.frequencyPct, ) countGlyphs.append(countGlyph) if glyph.absEmsRawAverage > 0.03: avgGlyph = TFSMap(glyph) avgGlyph.sortValue = glyph.absEmsRawAverage avgGlyph.displayValue = '%0.2f em' % (glyph.absEmsRawAverage, ) # avgGlyph.displayValue = '%0.2f%%' % (100.0 * glyph.absEmsRawAverage, ) avgGlyphs.append(avgGlyph) self.dumpMetricsGroup(countGlyphs, 'Most Common Kerning Pairs', 'The most frequent kerning pairs.', 'most_common_kerning_pairs_avg.html') self.dumpMetricsGroup(avgGlyphs, 'Most Heavily Kerning Pairs', 'The most heavily kerning pairs.', 'most_heavily_kerning_pairs_avg.html')
def getCommandLineSettings(*replacementValues): def assertExists(value): if not os.path.exists(value): msg = "%s does not exist" % value raise argparse.ArgumentTypeError(msg) def assertParentExists(value): if not (os.path.exists(os.path.dirname(value)) and os.path.isdir(os.path.dirname(value))): msg = "%s is not a valid directory" % os.path.dirname(value) raise argparse.ArgumentTypeError(msg) def assertIsFolder(value): assertExists(value) if not os.path.isdir(value): msg = "%s is not a folder" % value raise argparse.ArgumentTypeError(msg) def folderType(value): assertIsFolder(value) return value # return os.path.abspath(value) def assertFileExtension(value, extension): basename = os.path.basename(value) if not basename.lower().endswith(extension.lower()): msg = "%s is not a %s file" % ( value, extension, ) raise argparse.ArgumentTypeError(msg) def ufoSrcFolderType(value): assertIsFolder(value) assertFileExtension(value, '.ufo') return value # return os.path.abspath(value) def ufoDstFolderType(value): assertParentExists(value) assertFileExtension(value, '.ufo') # return os.path.abspath(value) return value def otfDstFileType(value): assertParentExists(value) assertFileExtension(value, '.otf') return value # return os.path.abspath(value) parser = argparse.ArgumentParser(description='') parser.add_argument('--ufo-src-path', type=ufoSrcFolderType, help='The .ufo source file to kern.', # ) # TODO: required=True) parser.add_argument('--ufo-dst-path', type=ufoDstFolderType, help='The .ufo destination file.', # ) # TODO: required=True) parser.add_argument('--otf-dst', type=otfDstFileType, help='Optional OpenType (.otf) destination file.', ) # TODO: # required=True) parser.add_argument('--log-path', type=folderType, help='Optional folder in which to write HTML logs. CAUTION: This folder will be completely overwritten.') parser.add_argument('--default-diacritical-distance-ems', type=float, default=0.065, help='The default distance between a glyph and its diacritical in ems. 0.0 <= x <= 1.0. Default: 0.065 em') parser.add_argument('--top-join-centers', nargs='*', help='A list of custom (unicode code point, horizontal center value) pairs used for top-aligned diacriticals. To center the diacritical Grave (unicode: 0x60) 100 units right of its origin, use --top-join-centers 0x60 100. Accepts an arbitrary number of pairs.') parser.add_argument('--tail-join-centers', nargs='*', help='A list of custom (unicode code point, horizontal center value) pairs used for tail-aligned diacriticals. To center the diacritical Ogonek (unicode: 0x2DB) 100 units right of its origin, use --tail-join-centers 0x2DB 100. Accepts an arbitrary number of pairs.') parser.add_argument('--middle-join-centers', nargs='*', help='A list of custom (unicode code point, horizontal center value) pairs used for middle-aligned diacriticals. To center the diacritical Middle Dot (unicode: 0xB7) 100 units right of its origin, use --middle-join-centers 0xB7 100. Accepts an arbitrary number of pairs.') if replacementValues: args = parser.parse_args(replacementValues) else: args = parser.parse_args() # print 'args', args result = TFSMap() result.ufo_src_path = args.ufo_src result.ufo_dst_path = args.ufo_dst result.otf_dst = args.otf_dst result.log_path = args.log_dst result.default_diacritical_distance_ems = args.default_diacritical_distance_ems result.top_join_centers = args.top_join_centers if result.top_join_centers is not None: if len(result.top_join_centers) % 2 != 0: raise Exception('--top-join-centers requires an even number of values.') result.tail_join_centers = args.tail_join_centers if result.tail_join_centers is not None: if len(result.tail_join_centers) % 2 != 0: raise Exception('--tail-join-centers requires an even number of values.') result.middle_join_centers = args.middle_join_centers if result.middle_join_centers is not None: if len(result.middle_join_centers) % 2 != 0: raise Exception('--middle-join-centers requires an even number of values.') # print 'args.top_join_centers', args.custom_glyph_centers # import sys # sys.exit(0) return result
def _makeUnicodedataCategoryMap(): ''' http://bugs.python.org/file19991/unicodedata-doc.diff + +--------------------------------------------------------------------------+ + | **General Categories** | + +----+-------------+------------------+------------------------------------+ + |Name|Major |Minor |Examples | + +====+=============+==================+====================================+ + |Lu | Letter | uppercase | | + +----+-------------+------------------+------------------------------------+ + |Ll | Letter | lowercase | | + +----+-------------+------------------+------------------------------------+ + |Lt | Letter | titlecase | | + +----+-------------+------------------+------------------------------------+ + |Lm | Letter | modifier | | + +----+-------------+------------------+------------------------------------+ + |Lo | Letter | other | | + +----+-------------+------------------+------------------------------------+ + |Mn | Mark | nonspacing | | + +----+-------------+------------------+------------------------------------+ + |Mc | Mark | spacing combining| | + +----+-------------+------------------+------------------------------------+ + |Me | Mark | enclosing | | + +----+-------------+------------------+------------------------------------+ + |Nd | Number | decimal digit | | + +----+-------------+------------------+------------------------------------+ + |Nl | Number | letter | | + +----+-------------+------------------+------------------------------------+ + |No | Number | other | | + +----+-------------+------------------+------------------------------------+ + |Pc | Punctuation | connector | | + +----+-------------+------------------+------------------------------------+ + |Pd | Punctuation | dash | | + +----+-------------+------------------+------------------------------------+ + |Ps | Punctuation | open | | + +----+-------------+------------------+------------------------------------+ + |Pe | Punctuation | close | | + +----+-------------+------------------+------------------------------------+ + |Pi | Punctuation | initial quote | | + +----+-------------+------------------+------------------------------------+ + |Pf | Punctuation | final quote | | + +----+-------------+------------------+------------------------------------+ + |Po | Punctuation | other | | + +----+-------------+------------------+------------------------------------+ + |Sm | Symbol | math | | + +----+-------------+------------------+------------------------------------+ + |Sc | Symbol | currency | | + +----+-------------+------------------+------------------------------------+ + |Sk | Symbol | modifier | | + +----+-------------+------------------+------------------------------------+ + |So | Symbol | other | | + +----+-------------+------------------+------------------------------------+ + |Zs | Separator | space | | + +----+-------------+------------------+------------------------------------+ + |Zl | Separator | line | | + +----+-------------+------------------+------------------------------------+ + |Zp | Separator | paragraph | | + +----+-------------+------------------+------------------------------------+ + |Cc | Other | control | | + +----+-------------+------------------+------------------------------------+ + |Cf | Other | format | | + +----+-------------+------------------+------------------------------------+ + |Cs | Other | surrogate | | + +----+-------------+------------------+------------------------------------+ + |Co | Other | private use | | + +----+-------------+------------------+------------------------------------+ + |Cn | Other | not assigned | | + +----+-------------+------------------+------------------------------------+ ''' result = {} for name, major, minor in ( ( 'Lu', 'Letter', 'uppercase',), ( 'Ll', 'Letter', 'lowercase',), ( 'Lt', 'Letter', 'titlecase',), ( 'Lm', 'Letter', 'modifier',), ( 'Lo', 'Letter', 'other',), ( 'Mn', 'Mark', 'nonspacing',), ( 'Mc', 'Mark', 'spacing combining',), ( 'Me', 'Mark', 'enclosing',), ( 'Nd', 'Number', 'decimal digit',), ( 'Nl', 'Number', 'letter',), ( 'No', 'Number', 'other',), ( 'Pc', 'Punctuation', 'connector',), ( 'Pd', 'Punctuation', 'dash',), ( 'Ps', 'Punctuation', 'open',), ( 'Pe', 'Punctuation', 'close',), ( 'Pi', 'Punctuation', 'initial quote',), ( 'Pf', 'Punctuation', 'final quote',), ( 'Po', 'Punctuation', 'other',), ( 'Sm', 'Symbol', 'math',), ( 'Sc', 'Symbol', 'currency',), ( 'Sk', 'Symbol', 'modifier',), ( 'So', 'Symbol', 'other',), ( 'Zs', 'Separator', 'space',), ( 'Zl', 'Separator', 'line',), ( 'Zp', 'Separator', 'paragraph',), ( 'Cc', 'Other', 'control',), ( 'Cf', 'Other', 'format',), ( 'Cs', 'Other', 'surrogate',), ( 'Co', 'Other', 'private use',), ( 'Cn', 'Other', 'not assigned',), ): category = TFSMap() category.name = name category.major = major category.minor = minor result[category.name] = category return result
def dumpMetrics(self): print print 'fonts scanned:', len(self.processedPostscriptNames) print 'fonts processed:', len(self.nonEmptyPostscriptNames) print 'glyphs observed:', len(self.glyphCountMap) maxGlyphCount = reduce(max, self.glyphCountMap.values()) print 'Highest glyph frequency:', maxGlyphCount glyphs = [] for codePoint, count in self.glyphCountMap.iteritems(): glyph = TFSMap() glyph.codePoint = codePoint glyph.count = count glyphs.append(glyph) def glyphCountSort(glyph0, glyph1): # Negate; we want reverse order for count. result = -cmp(glyph0.count, glyph1.count) if result != 0: return result return cmp(glyph0.codePoint, glyph1.codePoint) glyphs.sort(glyphCountSort) print 'Most common glyph:', glyphs[0] print 'Least common glyph:', glyphs[-1] locale.setlocale(locale.LC_ALL, 'en_US') pres = [] for glyph in glyphs[:1000]: # pre = {} pre = { # 'glyphHex': hex(glyph.codePoint), 'glyphHex': '%04X' % glyph.codePoint, 'glyphName': getUnicodeLongName(glyph.codePoint, ignoreUnknown=True, skipValidation=True), 'glyphCount': locale.format("%d", glyph.count, grouping=True), 'glyphPercent': '%0.2f%%' % (100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames))), # 'glyphColor': '%06X' % glyphColor, } # pre['value'] = '%s %s: %d (%0.2f%%)' % ( hex(glyph.codePoint), # getUnicodeLongName(glyph.codePoint, # ignoreUnknown=True, # skipValidation=True), # glyph.count, # glyph.count / float(len(self.nonEmptyPostscriptNames)), # ) # print 'pre', pre pres.append(pre) glyphs.sort(lambda glyph0, glyph1:cmp(glyph0.codePoint, glyph1.codePoint)) headerPres = [] for glyph in glyphs[:10000]: minGlyphColor = 0xffafafff maxGlyphColor = 0xff0f0f5f phase = glyph.count / float(maxGlyphCount) from tfs.common.TFSSvg import blendArgbColors glyphColor = 0xffffff & blendArgbColors(minGlyphColor, maxGlyphColor, phase) pre = { # 'glyphHex': hex(glyph.codePoint), 'glyphHex': '%X' % glyph.codePoint, 'glyphName': getUnicodeLongName(glyph.codePoint, ignoreUnknown=True, skipValidation=True), 'glyphCount': locale.format("%d", glyph.count, grouping=True), 'glyphPercent': '%0.2f%%' % (100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames))), 'glyphColor': '%06X' % glyphColor, } # pre['value'] = '%s %s: %d (%0.2f%%)' % ( hex(glyph.codePoint), # getUnicodeCharacterName(glyph.codePoint, # ignoreUnknown=True, # skipValidation=True), # glyph.count, # glyph.count / float(len(self.nonEmptyPostscriptNames)), # ) # print 'pre', pre headerPres.append(pre) # tableSvg = self.getTableSvg(glyphs, maxGlyphCount) self.writeMustacheLog('gia_pre_template.txt', 'most_common_glyphs.html', mustacheVars = { 'pres': pres, 'headerPres': headerPres, 'pageTitle': '1,000 Most Commonly Implemented Font Glyphs', 'headerTitle': 'Glyph Implementation Statistics', 'statsTitle': 'Statistics', 'stats': ( { 'key': 'Total Fonts Scanned', 'value': locale.format("%d", len(self.processedPostscriptNames), grouping=True), }, { 'key': 'Distinct Code Points Observed', 'value': locale.format("%d", len(self.glyphCountMap), grouping=True), }, ), } # replaceMap = {'<!-- SVG Graph Placeholder -->': tableSvg, # } )
def getGlyphInfos(self): result = [] # glyphIndexToNameMap = {} glyphToCharacterMap = self.getGlyphIndexToCharacterMap() if self.ftFont.has_glyph_names: for glyphIndex in self.getGlyphIndices(): glyphNameBuffer = ' ' * 256 error = freetype.FT_Get_Glyph_Name(self.ftFont._FT_Face, glyphIndex, glyphNameBuffer, len(glyphNameBuffer) - 1) if error: raise freetype.FT_Exception(error) glyphInfo = TFSMap() glyphInfo.glyphIndex = glyphIndex glyphInfo.glyphName = glyphNameBuffer.strip()[:-1] # print 'glyphName', glyphIndex, glyphName, len(glyphName) glyphInfo.characterCode = None if glyphIndex in glyphToCharacterMap: glyphInfo.characterCode = glyphToCharacterMap[glyphIndex] result.append(glyphInfo) else: for glyphIndex, characterCode in glyphToCharacterMap.items(): glyphInfo = TFSMap() glyphInfo.glyphIndex = glyphIndex glyphInfo.glyphName = getUnicodeCharacterName(characterCode) glyphInfo.characterCode = characterCode # glyphInfoMap[glyphIndex] = glyphInfo result.append(glyphInfo) return result
def dumpMetricsMap(self, kerningPairMap, htmlFilename): print print 'fonts scanned:', len(self.processedPostscriptNames) print 'fonts processed:', len(self.nonEmptyPostscriptNames) print 'glyph pairs observed:', len(kerningPairMap) maxGlyphPairCount = reduce(max, kerningPairMap.values()) print 'Highest glyph pair frequency:', maxGlyphPairCount glyphs = [] for (glyph0, glyph1,), count in kerningPairMap.iteritems(): glyph = TFSMap() glyph.glyph0 = glyph0 glyph.glyph1 = glyph1 glyph.count = count glyphs.append(glyph) def glyphCountSort(glyph0, glyph1): # Negate; we want reverse order for count. result = -cmp(glyph0.count, glyph1.count) if result != 0: return result result = cmp(glyph0.glyph0, glyph1.glyph0) if result != 0: return result result = cmp(glyph0.glyph1, glyph1.glyph1) if result != 0: return result return 0 # return cmp(glyph0.codePoint, glyph1.codePoint) glyphs.sort(glyphCountSort) print 'Most common glyph:', glyphs[0] print 'Least common glyph:', glyphs[-1] locale.setlocale(locale.LC_ALL, 'en_US') pres = [] for glyph in glyphs[:5000]: # for glyph in glyphs[:1000]: # pre = {} pre = { # 'glyphHex': hex(glyph.codePoint), 'glyphHex0': '%04X' % glyph.glyph0, 'glyphHex1': '%04X' % glyph.glyph1, # 'glyphName0': getUnicodeLongName(glyph.glyph0, # ignoreUnknown=True, # skipValidation=True), # 'glyphName1': getUnicodeLongName(glyph.glyph1, # ignoreUnknown=True, # skipValidation=True), 'glyphName0': getUnicodeCharacterName(glyph.glyph0, ignoreUnknown=True), 'glyphName1': getUnicodeCharacterName(glyph.glyph1, ignoreUnknown=True), 'glyphCount': locale.format("%d", glyph.count, grouping=True), 'glyphPercent': '%0.2f%%' % (100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames))), # 'glyphColor': '%06X' % glyphColor, } # pre['value'] = '%s %s: %d (%0.2f%%)' % ( hex(glyph.codePoint), # getUnicodeLongName(glyph.codePoint, # ignoreUnknown=True, # skipValidation=True), # glyph.count, # glyph.count / float(len(self.nonEmptyPostscriptNames)), # ) # print 'pre', pre pres.append(pre) self.writeMustacheLog('kia_pre_template.txt', htmlFilename, # 'most_common_kerning_pairs.html', mustacheVars={ 'pres': pres, # 'headerPres': headerPres, 'pageTitle': '1,000 Most Common Kerning Pairs', 'headerTitle': '1,000 Most Common Kerning Pairs', # 'headerTitle': 'Kerning Pairs Implementation Statistics', 'statsTitle': 'Statistics', 'stats': ( { 'key': 'Total Fonts', 'value': locale.format("%d", len(self.processedPostscriptNames), grouping=True), }, { 'key': 'Fonts With Valid Kerning Table', 'value': locale.format("%d", len(self.nonEmptyPostscriptNames), grouping=True), }, { 'key': 'Kerning Pairs Observed', 'value': locale.format("%d", len(kerningPairMap), grouping=True), }, ), } # replaceMap = {'<!-- SVG Graph Placeholder -->': tableSvg, # } )
def dumpMetrics(self): print print 'fonts scanned:', len(self.processedPostscriptNames) print 'fonts processed:', len(self.nonEmptyPostscriptNames) print 'glyph pairs observed:', len(self.kerningPairCountMap) maxGlyphPairCount = reduce(max, self.kerningPairCountMap.values()) print 'Highest glyph pair frequency:', maxGlyphPairCount # self.dumpMetricsMap(self.kerningPairCountMap, 'most_common_kerning_pairs.html') # self.dumpMetricsMap(self.kerningPairAbsEmsMap, 'most_common_kerning_pairs_ems.html') # kerningPairAverageMap = {} # for key in self.kerningPairCountMap: # kerningPairAverageMap[key] = self.kerningPairAbsEmsMap[key] / self.kerningPairCountMap[key] # self.dumpMetricsMap(kerningPairAverageMap, 'most_common_kerning_pairs_avg.html') countGlyphs = [] avgGlyphs = [] for key in self.kerningPairCountMap: glyph0, glyph1 = key glyph = TFSMap() glyph.glyph0 = glyph0 glyph.glyph1 = glyph1 glyph.absEmsTotal = self.kerningPairAbsEmsMap[key] glyph.count = self.kerningPairCountMap[key] glyph.frequencyPct = 100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames)) glyph.absEmsRawAverage = self.kerningPairAbsEmsMap[key] / float(len(self.nonEmptyPostscriptNames)) glyph.absEmsWeightedAverage = self.kerningPairAbsEmsMap[key] / float(self.kerningPairCountMap[key]) glyphHex0 = '%04X' % glyph.glyph0 glyphHex1 = '%04X' % glyph.glyph1 def getGlyphName(codePoint): result = getUnicodeCharacterName(codePoint, ignoreUnknown=True, skipValidation=True) if result is None: return 'Unknown' result = result.replace('<', '').replace('>', '') return result glyph.label = '0x%s &#x%s %s vs. 0x%s &#x%s %s' % ( glyphHex0, glyphHex0, getGlyphName(glyph.glyph0), glyphHex1, glyphHex1, getGlyphName(glyph.glyph1), ) # 'glyphCount': locale.format("%d", glyph.count, grouping=True), # 'glyphPercent': '%0.2f%%' % (100.0 * glyph.count / float(len(self.nonEmptyPostscriptNames))), if glyph.frequencyPct >= 10.0: countGlyph = TFSMap(glyph) countGlyph.sortValue = glyph.count countGlyph.displayValue = glyph.count countGlyph.displayValue = '%0.0f%%' % ( glyph.frequencyPct, ) countGlyphs.append(countGlyph) if glyph.absEmsRawAverage > 0.03: avgGlyph = TFSMap(glyph) avgGlyph.sortValue = glyph.absEmsRawAverage avgGlyph.displayValue = '%0.2f em' % (glyph.absEmsRawAverage,) # avgGlyph.displayValue = '%0.2f%%' % (100.0 * glyph.absEmsRawAverage, ) avgGlyphs.append(avgGlyph) self.dumpMetricsGroup(countGlyphs, 'Most Common Kerning Pairs', 'The most frequent kerning pairs.', 'most_common_kerning_pairs_avg.html') self.dumpMetricsGroup(avgGlyphs, 'Most Heavily Kerning Pairs', 'The most heavily kerning pairs.', 'most_heavily_kerning_pairs_avg.html')
def _makeUnicodedataCategoryMap(): ''' http://bugs.python.org/file19991/unicodedata-doc.diff + +--------------------------------------------------------------------------+ + | **General Categories** | + +----+-------------+------------------+------------------------------------+ + |Name|Major |Minor |Examples | + +====+=============+==================+====================================+ + |Lu | Letter | uppercase | | + +----+-------------+------------------+------------------------------------+ + |Ll | Letter | lowercase | | + +----+-------------+------------------+------------------------------------+ + |Lt | Letter | titlecase | | + +----+-------------+------------------+------------------------------------+ + |Lm | Letter | modifier | | + +----+-------------+------------------+------------------------------------+ + |Lo | Letter | other | | + +----+-------------+------------------+------------------------------------+ + |Mn | Mark | nonspacing | | + +----+-------------+------------------+------------------------------------+ + |Mc | Mark | spacing combining| | + +----+-------------+------------------+------------------------------------+ + |Me | Mark | enclosing | | + +----+-------------+------------------+------------------------------------+ + |Nd | Number | decimal digit | | + +----+-------------+------------------+------------------------------------+ + |Nl | Number | letter | | + +----+-------------+------------------+------------------------------------+ + |No | Number | other | | + +----+-------------+------------------+------------------------------------+ + |Pc | Punctuation | connector | | + +----+-------------+------------------+------------------------------------+ + |Pd | Punctuation | dash | | + +----+-------------+------------------+------------------------------------+ + |Ps | Punctuation | open | | + +----+-------------+------------------+------------------------------------+ + |Pe | Punctuation | close | | + +----+-------------+------------------+------------------------------------+ + |Pi | Punctuation | initial quote | | + +----+-------------+------------------+------------------------------------+ + |Pf | Punctuation | final quote | | + +----+-------------+------------------+------------------------------------+ + |Po | Punctuation | other | | + +----+-------------+------------------+------------------------------------+ + |Sm | Symbol | math | | + +----+-------------+------------------+------------------------------------+ + |Sc | Symbol | currency | | + +----+-------------+------------------+------------------------------------+ + |Sk | Symbol | modifier | | + +----+-------------+------------------+------------------------------------+ + |So | Symbol | other | | + +----+-------------+------------------+------------------------------------+ + |Zs | Separator | space | | + +----+-------------+------------------+------------------------------------+ + |Zl | Separator | line | | + +----+-------------+------------------+------------------------------------+ + |Zp | Separator | paragraph | | + +----+-------------+------------------+------------------------------------+ + |Cc | Other | control | | + +----+-------------+------------------+------------------------------------+ + |Cf | Other | format | | + +----+-------------+------------------+------------------------------------+ + |Cs | Other | surrogate | | + +----+-------------+------------------+------------------------------------+ + |Co | Other | private use | | + +----+-------------+------------------+------------------------------------+ + |Cn | Other | not assigned | | + +----+-------------+------------------+------------------------------------+ ''' result = {} for name, major, minor in ( ( 'Lu', 'Letter', 'uppercase', ), ( 'Ll', 'Letter', 'lowercase', ), ( 'Lt', 'Letter', 'titlecase', ), ( 'Lm', 'Letter', 'modifier', ), ( 'Lo', 'Letter', 'other', ), ( 'Mn', 'Mark', 'nonspacing', ), ( 'Mc', 'Mark', 'spacing combining', ), ( 'Me', 'Mark', 'enclosing', ), ( 'Nd', 'Number', 'decimal digit', ), ( 'Nl', 'Number', 'letter', ), ( 'No', 'Number', 'other', ), ( 'Pc', 'Punctuation', 'connector', ), ( 'Pd', 'Punctuation', 'dash', ), ( 'Ps', 'Punctuation', 'open', ), ( 'Pe', 'Punctuation', 'close', ), ( 'Pi', 'Punctuation', 'initial quote', ), ( 'Pf', 'Punctuation', 'final quote', ), ( 'Po', 'Punctuation', 'other', ), ( 'Sm', 'Symbol', 'math', ), ( 'Sc', 'Symbol', 'currency', ), ( 'Sk', 'Symbol', 'modifier', ), ( 'So', 'Symbol', 'other', ), ( 'Zs', 'Separator', 'space', ), ( 'Zl', 'Separator', 'line', ), ( 'Zp', 'Separator', 'paragraph', ), ( 'Cc', 'Other', 'control', ), ( 'Cf', 'Other', 'format', ), ( 'Cs', 'Other', 'surrogate', ), ( 'Co', 'Other', 'private use', ), ( 'Cn', 'Other', 'not assigned', ), ): category = TFSMap() category.name = name category.major = major category.minor = minor result[category.name] = category return result