diff --git a/font-patcher b/font-patcher index 0d542b42cc..2c5ec3982d 100755 --- a/font-patcher +++ b/font-patcher @@ -6,7 +6,7 @@ from __future__ import absolute_import, print_function, unicode_literals # Change the script version when you edit this script: -script_version = "3.4.4" +script_version = "3.4.5" version = "2.3.0" projectName = "Nerd Fonts" @@ -36,7 +36,6 @@ except ImportError: ) ) -# This is for experimenting sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])) + '/bin/scripts/name_parser/') try: from FontnameParser import FontnameParser @@ -187,15 +186,23 @@ def check_panose_monospaced(font): (panose[0] == 3 and panose[3] == 3)) return 1 if panose_mono else 0 +def panose_check_to_text(value, panose = False): + """ Convert value from check_panose_monospaced() to human readable string """ + if value == 0: + return "Panose says \"not monospaced\"" + if value == 1: + return "Panose says \"monospaced\"" + return "Panose is invalid" + (" ({})".format(list(panose)) if panose else "") + def is_monospaced(font): """ Check if a font is probably monospaced """ # Some fonts lie (or have not any Panose flag set), spot check monospaced: width = -1 width_mono = True - for glyph in [ 0x49, 0x4D, 0x57, 0x61, 0x69, 0x2E ]: # wide and slim glyphs 'I', 'M', 'W', 'a', 'i', '.' + for glyph in [ 0x49, 0x4D, 0x57, 0x61, 0x69, 0x6d, 0x2E ]: # wide and slim glyphs 'I', 'M', 'W', 'a', 'i', 'm', '.' if not glyph in font: # A 'strange' font, believe Panose - return check_panose_monospaced(font) == 1 + return (check_panose_monospaced(font) == 1, None) # print(" -> {} {}".format(glyph, font[glyph].width)) if width < 0: width = font[glyph].width @@ -213,7 +220,7 @@ def is_monospaced(font): width_mono = False break # We believe our own check more then Panose ;-D - return width_mono + return (width_mono, None if width_mono else glyph) def get_advance_width(font, extended, minimum): """ Get the maximum/minimum advance width in the extended(?) range """ @@ -236,6 +243,11 @@ def get_advance_width(font, extended, minimum): width = font[glyph].width return width +def report_advance_widths(font): + return "Advance widths (base/extended): {} - {} / {} - {}".format( + get_advance_width(font, True, True), get_advance_width(font, False, True), + get_advance_width(font, False, False), get_advance_width(font, True, False)) + class font_patcher: def __init__(self, args): @@ -673,15 +685,18 @@ class font_patcher: def assert_monospace(self): # Check if the sourcefont is monospaced - width_mono = is_monospaced(self.sourceFont) + width_mono, offending_char = is_monospaced(self.sourceFont) panose_mono = check_panose_monospaced(self.sourceFont) # The following is in fact "width_mono != panose_mono", but only if panose_mono is not 'unknown' if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1): print(" Warning: Monospaced check: Panose assumed to be wrong") - print(" Glyph widths {} / {} - {} and Panose says \"monospace {}\" ({})".format(get_advance_width(self.sourceFont, False, True), - get_advance_width(self.sourceFont, False, False), get_advance_width(self.sourceFont, True, False), panose_mono, list(self.sourceFont.os2_panose))) + print(" {} and {}".format( + report_advance_widths(self.sourceFont), + panose_check_to_text(panose_mono, self.sourceFont.os2_panose))) if not width_mono: print(" Warning: Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless") + if offending_char is not None: + print(" Offending char: 0x{:X}".format(offending_char)) if self.args.single <= 1: sys.exit(projectName + ": Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching") @@ -963,16 +978,15 @@ class font_patcher: self.sourceFont.os2_typodescent = self.sourceFont.os2_typodescent - gap_bottom # TODO Check what to do with win and hhea values - # Find the biggest char width - # Ignore the y-values, os2_winXXXXX values set above are used for line height - # + # Find the biggest char width and advance width # 0x00-0x17f is the Latin Extended-A range warned = self.args.quiet or self.args.nonmono # Do not warn if quiet or proportional target for glyph in range(0x21, 0x17f): if glyph in range(0x7F, 0xBF) or glyph in [ - 0x132, 0x134, # IJ, ij (in Overpass Mono) + 0x132, 0x133, # IJ, ij (in Overpass Mono) 0x022, 0x027, 0x060, # Single and double quotes in Inconsolata LGC 0x0D0, 0x10F, 0x110, 0x111, 0x127, 0x13E, 0x140, 0x165, # Eth and others with stroke or caron in RobotoMono + 0x02D, # hyphen for Monofur ]: continue # ignore special characters like '1/4' etc and some specifics try: @@ -983,12 +997,13 @@ class font_patcher: if self.font_dim['width'] < self.sourceFont[glyph].width: self.font_dim['width'] = self.sourceFont[glyph].width if not warned and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z - print("Extended glyphs wider than basic glyphs") + print("Warning: Extended glyphs wider than basic glyphs, results might be useless\n {}".format( + report_advance_widths(self.sourceFont))) warned = True - # print("New MAXWIDTH-A {} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) + # print("New MAXWIDTH-A {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) if xmax > self.font_dim['xmax']: self.font_dim['xmax'] = xmax - # print("New MAXWIDTH-B {} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) + # print("New MAXWIDTH-B {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) # print("FINAL", self.font_dim)