Skip to content

Commit

Permalink
font-patcher: Introduce weight check
Browse files Browse the repository at this point in the history
[why]
Windows seems to construct the font names including the PS weight.
We have some sourcefonts that are broken (i.e. have in fact different
weights but have the same PS weight and/or OS2 weight.

That raises problems with the fonts on Windows.

[how]
Check and compare all weight metadata (except CID) and issue a warning
if they differ too much. That might fail with unusual weight names,
though.

See Issue #1333 and PR #1358.

Reported-by: LeoniePhiline
Signed-off-by: Fini Jastrow <[email protected]>
  • Loading branch information
Finii committed Sep 27, 2023
1 parent 4c6cabe commit 4fe686d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 4 deletions.
22 changes: 22 additions & 0 deletions bin/scripts/name_parser/FontnameParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,34 @@ def checklen(self, max_len, entry_id, name):
self.logger.error('====-< {:18} too long ({:2} > {:2}): {}'.format(entry_id, len(name), max_len, name))
return name

def check_weights(self, font):
""" Check weight metadata for consistency """
# Some weights are hidden in styles
ignore_token = list(FontnameTools.known_widths) + list(FontnameTools.known_slopes)
ignore_token += [ m + s
for s in list(FontnameTools.known_widths)
for m in list(FontnameTools.known_modifiers) ]
restored_weight_token = [ w for w in self.style_token + self.weight_token if w not in ignore_token ]
weight = ''.join(restored_weight_token)
os2_weight = font.os2_weight
ps_weight = FontnameTools.weight_string_to_number(font.weight)
name_weight = FontnameTools.weight_string_to_number(weight)
if name_weight is None:
self.logger.error('Can not parse name for weight: {}'.format(restored_weight_token))
return
if abs(os2_weight - ps_weight) > 50 or abs(os2_weight - name_weight) > 50:
self.logger.warning('Possible problem with the weight metadata detected, check with --debug')
self.logger.debug('Weight approximations: OS2/PS/Name: {}/{}/{} (from {}/\'{}\'/\'{}\')'.format(
os2_weight, ps_weight, name_weight,
font.os2_weight, font.weight, weight))

def rename_font(self, font):
"""Rename the font to include all information we found (font is fontforge font object)"""
font.fondname = None
font.fontname = self.psname()
font.fullname = self.fullname()
font.familyname = self.ps_familyname()
self.check_weights(font)

# We have to work around several issues in fontforge:
#
Expand Down
51 changes: 48 additions & 3 deletions bin/scripts/name_parser/FontnameTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ def postscript_char_filter(name):
'Light': ('Lt', 'Light'),
' ': (), # Just for CodeClimate :-/
}
known_styles = [ # Keywords that end up as style (i.e. a RIBBI set)
'Bold', 'Italic', 'Regular', 'Normal'
]
known_widths = { # can take modifiers
'Compressed': ('Cm', 'Comp'),
'Extended': ('Ex', 'Extd'),
Expand All @@ -268,6 +271,49 @@ def postscript_char_filter(name):
'Semi': ('Sm', 'Sem'),
'Extra': ('X', 'Ext'),
}
equivalent_weights = {
100: ('thin', 'hairline'),
200: ('extralight', 'ultralight'),
300: ('light', ),
350: ('semilight', ),
400: ('regular', 'normal', 'book', 'text', 'nord', 'retina'),
500: ('medium', ),
600: ('semibold', 'demibold', 'demi'),
700: ('bold', ),
800: ('extrabold', 'ultrabold'),
900: ('black', 'heavy', 'poster', 'extrablack', 'ultrablack'),
}

@staticmethod
def weight_string_to_number(w):
""" Convert a common string approximation to a PS/2 weight value """
if not len(w):
return 400
for num, strs in FontnameTools.equivalent_weights.items():
if w.lower() in strs:
return num
return None

@staticmethod
def weight_to_string(w):
""" Convert a PS/2 weight value to the common string approximation """
if w < 150:
return "Thin"
if w < 250:
return "Extra-Light"
if w < 350:
return "Light"
if w < 450:
return "Regular"
if w < 550:
return "Medium"
if w < 650:
return "Semi-Bold"
if w < 750:
return "Bold"
if w < 850:
return "Extra-Bold"
return "Black"

@staticmethod
def is_keep_regular(basename):
Expand Down Expand Up @@ -342,8 +388,7 @@ def parse_font_name(name):
for s in list(FontnameTools.known_weights2) + list(FontnameTools.known_widths)
for m in list(FontnameTools.known_modifiers) + [''] if m != s
] + list(FontnameTools.known_weights1) + list(FontnameTools.known_slopes)
styles = [ 'Bold', 'Italic', 'Regular', 'Normal', ]
weights = [ w for w in weights if w not in styles ]
weights = [ w for w in weights if w not in FontnameTools.known_styles ]
# Some font specialities:
other = [
'-', 'Book', 'For', 'Powerline',
Expand All @@ -355,7 +400,7 @@ def parse_font_name(name):
]

( style, weight_token ) = FontnameTools.get_name_token(style, weights)
( style, style_token ) = FontnameTools.get_name_token(style, styles)
( style, style_token ) = FontnameTools.get_name_token(style, FontnameTools.known_styles)
( style, other_token ) = FontnameTools.get_name_token(style, other)
while 'Regular' in style_token and len(style_token) > 1:
# Correct situation where "Regular" and something else is given
Expand Down
2 changes: 1 addition & 1 deletion font-patcher
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from __future__ import absolute_import, print_function, unicode_literals

# Change the script version when you edit this script:
script_version = "4.5.1"
script_version = "4.5.2"

version = "3.0.2"
projectName = "Nerd Fonts"
Expand Down

0 comments on commit 4fe686d

Please sign in to comment.