mirror of
https://github.com/ryanoasis/nerd-fonts.git
synced 2025-01-06 21:49:40 +02:00
Merge pull request #1028 from ryanoasis/feature/reorganize-naming
Pull 'Mono' to front in names and other naming changes
This commit is contained in:
commit
20e7a8e390
14
.github/workflows/font-patcher.yml
vendored
14
.github/workflows/font-patcher.yml
vendored
@ -79,11 +79,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Check if patched font generated
|
- name: Check if patched font generated
|
||||||
run: |
|
run: |
|
||||||
[ -e "$GITHUB_WORKSPACE/temp/Hack Regular Nerd Font Complete.ttf" ] && echo "File exists" || exit 1
|
[ -e "$GITHUB_WORKSPACE/temp/HackNerdFont-Regular.ttf" ] && echo "File exists" || exit 1
|
||||||
|
|
||||||
- name: Setup Spot check font information 1
|
- name: Setup Spot check font information 1
|
||||||
run: |
|
run: |
|
||||||
echo FONT_INFO=$(fc-scan --format "%{family}:%{fullname}:%{style}\n" "$GITHUB_WORKSPACE/temp/Hack Regular Nerd Font Complete.ttf") >> $GITHUB_ENV
|
echo FONT_INFO=$(fc-scan --format "%{family}:%{fullname}:%{style}\n" "$GITHUB_WORKSPACE/temp/HackNerdFont-Regular.ttf") >> $GITHUB_ENV
|
||||||
|
|
||||||
# TODO fix issues setting and getting fullname and style with GITHUB_ENV :(
|
# TODO fix issues setting and getting fullname and style with GITHUB_ENV :(
|
||||||
- name: Setup Spot check font information 2
|
- name: Setup Spot check font information 2
|
||||||
@ -97,9 +97,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Spot check font properties
|
- name: Spot check font properties
|
||||||
run: |
|
run: |
|
||||||
${{ env.SHOWTTF }} -c "$GITHUB_WORKSPACE/temp/Hack Regular Nerd Font Complete.ttf" | grep -q 'File Checksum.*diff=0\s*$' && echo "TTF checksum ok" || exit 1
|
${{ env.SHOWTTF }} -c "$GITHUB_WORKSPACE/temp/HackNerdFont-Regular.ttf" | grep -q 'File Checksum.*diff=0\s*$' && echo "TTF checksum ok" || exit 1
|
||||||
ORIG_MINPPEM=$(${{ env.SHOWTTF }} -c "src/unpatched-fonts/Hack/Regular/Hack-Regular.ttf" | grep 'lowestppem=' )
|
ORIG_MINPPEM=$(${{ env.SHOWTTF }} -c "src/unpatched-fonts/Hack/Regular/Hack-Regular.ttf" | grep 'lowestppem=' )
|
||||||
PATCH_MINPPEM=$(${{ env.SHOWTTF }} -c "$GITHUB_WORKSPACE/temp/Hack Regular Nerd Font Complete.ttf" | grep 'lowestppem=' )
|
PATCH_MINPPEM=$(${{ env.SHOWTTF }} -c "$GITHUB_WORKSPACE/temp/HackNerdFont-Regular.ttf" | grep 'lowestppem=' )
|
||||||
echo "${ORIG_MINPPEM} == ${PATCH_MINPPEM}"
|
echo "${ORIG_MINPPEM} == ${PATCH_MINPPEM}"
|
||||||
[[ ${ORIG_MINPPEM} == ${PATCH_MINPPEM} ]] && echo "lowestRecPPEM matches" || exit 1
|
[[ ${ORIG_MINPPEM} == ${PATCH_MINPPEM} ]] && echo "lowestRecPPEM matches" || exit 1
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Check if patched font generated
|
- name: Check if patched font generated
|
||||||
run: |
|
run: |
|
||||||
[ -e "$GITHUB_WORKSPACE/temp/Hack Regular Nerd Font Complete Mono.ttf" ] && echo "File exists" || exit 1
|
[ -e "$GITHUB_WORKSPACE/temp/HackNerdFontMono-Regular.ttf" ] && echo "File exists" || exit 1
|
||||||
|
|
||||||
- name: Patcher OTF, Bold variant, and RFN compliance
|
- name: Patcher OTF, Bold variant, and RFN compliance
|
||||||
run: |
|
run: |
|
||||||
@ -121,11 +121,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Check if patched font generated
|
- name: Check if patched font generated
|
||||||
run: |
|
run: |
|
||||||
[ -e "$GITHUB_WORKSPACE/temp/Caskaydia Cove Bold Nerd Font Complete.otf" ] && echo "File exists" || exit 1
|
[ -e "$GITHUB_WORKSPACE/temp/CaskaydiaCoveNerdFont-Bold.otf" ] && echo "File exists" || exit 1
|
||||||
|
|
||||||
- name: Check if font with references is patched
|
- name: Check if font with references is patched
|
||||||
# (patch result not checked)
|
# (patch result not checked)
|
||||||
run: |
|
run: |
|
||||||
fontforge --script ./font-patcher src/unpatched-fonts/UbuntuMono/Regular/UbuntuMono-R.ttf \
|
fontforge --script ./font-patcher src/unpatched-fonts/UbuntuMono/Regular/UbuntuMono-R.ttf \
|
||||||
--quiet --no-progressbars --outputdir $GITHUB_WORKSPACE/temp/
|
--quiet --no-progressbars --outputdir $GITHUB_WORKSPACE/temp/
|
||||||
[ -e "$GITHUB_WORKSPACE/temp/Ubuntu Mono Nerd Font.ttf" ] && echo "File exists" || exit 1
|
[ -e "$GITHUB_WORKSPACE/temp/UbuntuMonoNerdFont-Regular.ttf" ] && echo "File exists" || exit 1
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Nerd Fonts Version: 2.3.3
|
# Nerd Fonts Version: 2.3.3
|
||||||
# Script Version: 1.2.1
|
# Script Version: 1.3.0
|
||||||
|
#
|
||||||
|
# You can supply options to the font-patcher via environment variable NERDFONTS
|
||||||
|
# That option will override the defaults (also defaults of THIS script).
|
||||||
|
|
||||||
# used for debugging
|
# used for debugging
|
||||||
# set -x
|
# set -x
|
||||||
@ -248,10 +251,10 @@ function patch_font {
|
|||||||
if [ "$config_has_powerline" -gt 0 ]
|
if [ "$config_has_powerline" -gt 0 ]
|
||||||
then
|
then
|
||||||
powerline=""
|
powerline=""
|
||||||
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --use-single-width-glyphs',}{' --windows',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --use-single-width-glyphs',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
||||||
else
|
else
|
||||||
powerline="--powerline"
|
powerline="--powerline"
|
||||||
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --powerline',}{' --use-single-width-glyphs',}{' --windows',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --powerline',}{' --use-single-width-glyphs',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd "$repo_root_dir" || {
|
cd "$repo_root_dir" || {
|
||||||
@ -260,19 +263,29 @@ function patch_font {
|
|||||||
}
|
}
|
||||||
# Use absolute path to allow fontforge being an AppImage (used in CI)
|
# Use absolute path to allow fontforge being an AppImage (used in CI)
|
||||||
PWD=`pwd`
|
PWD=`pwd`
|
||||||
|
# Create "Nerd Font"
|
||||||
if [ -n "${verbose}" ]
|
if [ -n "${verbose}" ]
|
||||||
then
|
then
|
||||||
echo "fontforge -quiet -script ${PWD}/font-patcher "$f" -q --also-windows $powerline $post_process --complete --no-progressbars --outputdir "${patched_font_dir}complete/" $config_patch_flags"
|
echo "fontforge -quiet -script ${PWD}/font-patcher "$f" -q $powerline $post_process -c --no-progressbars --outputdir "${patched_font_dir}complete/" $config_patch_flags ${NERDFONTS}"
|
||||||
fi
|
fi
|
||||||
{ OUT=$(fontforge -quiet -script ${PWD}/font-patcher "$f" -q --also-windows $powerline $post_process --complete --no-progressbars \
|
{ OUT=$(fontforge -quiet -script ${PWD}/font-patcher "$f" -q $powerline $post_process -c --no-progressbars \
|
||||||
--outputdir "${patched_font_dir}complete/" $config_patch_flags 2>&1 1>&3 3>&- ); } 3>&1
|
--outputdir "${patched_font_dir}complete/" $config_patch_flags ${NERDFONTS} 2>&1 1>&3 3>&- ); } 3>&1
|
||||||
if [ $? -ne 0 ]; then printf "$OUT\nPatcher run aborted!\n\n"; fi
|
if [ $? -ne 0 ]; then printf "$OUT\nPatcher run aborted!\n\n"; fi
|
||||||
|
# Create "Nerd Font Mono"
|
||||||
if [ -n "${verbose}" ]
|
if [ -n "${verbose}" ]
|
||||||
then
|
then
|
||||||
echo "fontforge -quiet -script ${PWD}/font-patcher "$f" -q -s ${font_config} --also-windows $powerline $post_process --complete --no-progressbars --outputdir "${patched_font_dir}complete/" $config_patch_flags"
|
echo "fontforge -quiet -script ${PWD}/font-patcher "$f" -q -s ${font_config} $powerline $post_process -c --no-progressbars --outputdir "${patched_font_dir}complete/" $config_patch_flags ${NERDFONTS}"
|
||||||
fi
|
fi
|
||||||
{ OUT=$(fontforge -quiet -script ${PWD}/font-patcher "$f" -q -s ${font_config} --also-windows $powerline $post_process --complete --no-progressbars \
|
{ OUT=$(fontforge -quiet -script ${PWD}/font-patcher "$f" -q -s ${font_config} $powerline $post_process -c --no-progressbars \
|
||||||
--outputdir "${patched_font_dir}complete/" $config_patch_flags 2>&1 1>&3 3>&- ); } 3>&1
|
--outputdir "${patched_font_dir}complete/" $config_patch_flags ${NERDFONTS} 2>&1 1>&3 3>&- ); } 3>&1
|
||||||
|
if [ $? -ne 0 ]; then printf "$OUT\nPatcher run aborted!\n\n"; fi
|
||||||
|
# Create "Nerd Font Propo"
|
||||||
|
if [ -n "${verbose}" ]
|
||||||
|
then
|
||||||
|
echo "fontforge -quiet -script ${PWD}/font-patcher "$f" -q --variable $powerline $post_process -c --no-progressbars --outputdir "${patched_font_dir}complete/" $config_patch_flags ${NERDFONTS}"
|
||||||
|
fi
|
||||||
|
{ OUT=$(fontforge -quiet -script ${PWD}/font-patcher "$f" -q --variable $powerline $post_process -c --no-progressbars \
|
||||||
|
--outputdir "${patched_font_dir}complete/" $config_patch_flags ${NERDFONTS} 2>&1 1>&3 3>&- ); } 3>&1
|
||||||
if [ $? -ne 0 ]; then printf "$OUT\nPatcher run aborted!\n\n"; fi
|
if [ $? -ne 0 ]; then printf "$OUT\nPatcher run aborted!\n\n"; fi
|
||||||
# wait for this group of background processes to finish to avoid forking too many processes
|
# wait for this group of background processes to finish to avoid forking too many processes
|
||||||
# that can add up quickly with the number of combinations
|
# that can add up quickly with the number of combinations
|
||||||
@ -325,10 +338,10 @@ function generate_info {
|
|||||||
if [ "$config_has_powerline" -gt 0 ]
|
if [ "$config_has_powerline" -gt 0 ]
|
||||||
then
|
then
|
||||||
powerline=""
|
powerline=""
|
||||||
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --use-single-width-glyphs',}{' --windows',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --use-single-width-glyphs',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
||||||
else
|
else
|
||||||
powerline="--powerline"
|
powerline="--powerline"
|
||||||
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --powerline',}{' --use-single-width-glyphs',}{' --windows',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
combinations=$(printf "./font-patcher ${f##*/} %s\\n" {' --powerline',}{' --use-single-width-glyphs',}{' --fontawesome',}{' --octicons',}{' --fontlogos',}{' --pomicons',}{' --powerlineextra',}{' --fontawesomeextension',}{' --powersymbols',}{' --weather',}{' --material',})
|
||||||
fi
|
fi
|
||||||
|
|
||||||
font_families_count=$((font_families_count+1))
|
font_families_count=$((font_families_count+1))
|
||||||
|
@ -7,38 +7,39 @@ from FontnameTools import FontnameTools
|
|||||||
class FontnameParser:
|
class FontnameParser:
|
||||||
"""Parse a font name and generate all kinds of names"""
|
"""Parse a font name and generate all kinds of names"""
|
||||||
|
|
||||||
def __init__(self, filename):
|
def __init__(self, filename, logger):
|
||||||
"""Parse a font filename and store the results"""
|
"""Parse a font filename and store the results"""
|
||||||
self.parse_ok = False
|
self.parse_ok = False
|
||||||
self.for_windows = False
|
self.use_short_families = (False, False, False) # ( camelcase name, short styles, aggressive )
|
||||||
self.use_short_families = (False, False) # ( camelcase name, short styles )
|
|
||||||
self.keep_regular_in_family = None # None = auto, True, False
|
self.keep_regular_in_family = None # None = auto, True, False
|
||||||
self.suppress_preferred_if_identical = True
|
self.suppress_preferred_if_identical = True
|
||||||
self.fullname_suff = ''
|
|
||||||
self.fontname_suff = ''
|
|
||||||
self.family_suff = ''
|
self.family_suff = ''
|
||||||
|
self.ps_fontname_suff = ''
|
||||||
|
self.short_family_suff = ''
|
||||||
self.name_subst = []
|
self.name_subst = []
|
||||||
[ self.parse_ok, self._basename, self.weight_token, self.style_token, self.other_token, self._rest ] = FontnameTools.parse_font_name(filename)
|
[ self.parse_ok, self._basename, self.weight_token, self.style_token, self.other_token, self._rest ] = FontnameTools.parse_font_name(filename)
|
||||||
self.basename = self._basename
|
self.basename = self._basename
|
||||||
self.rest = self._rest
|
self.rest = self._rest
|
||||||
self.add_name_substitution_table(FontnameTools.SIL_TABLE)
|
self.add_name_substitution_table(FontnameTools.SIL_TABLE)
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
def _make_ps_name(self, n, is_family):
|
def _make_ps_name(self, n, is_family):
|
||||||
"""Helper to limit font name length in PS names"""
|
"""Helper to limit font name length in PS names"""
|
||||||
fam = 'family ' if is_family else ''
|
fam = 'family ' if is_family else ''
|
||||||
if not self.for_windows or len(n) <= 31:
|
limit = 31 if is_family else 63
|
||||||
|
if len(n) <= limit:
|
||||||
return n
|
return n
|
||||||
r = re.search('(.*)(-.*)', n)
|
r = re.search('(.*)(-.*)', n)
|
||||||
if not r:
|
if not r:
|
||||||
new_n = n[:31]
|
new_n = n[:limit]
|
||||||
else:
|
else:
|
||||||
q = 31 - len(r.groups()[1])
|
q = limit - len(r.groups()[1])
|
||||||
if q < 1:
|
if q < 1:
|
||||||
q = 1
|
q = 1
|
||||||
print('Shortening too long PS {}name: Garbage warning'. format(fam))
|
self.logger.error('====-< Shortening too long PS {}name: Garbage warning'. format(fam))
|
||||||
new_n = r.groups()[0][:q] + r.groups()[1]
|
new_n = r.groups()[0][:q] + r.groups()[1]
|
||||||
if new_n != n:
|
if new_n != n:
|
||||||
print('Shortening too long PS {}name: {} -> {}'.format(fam, n, new_n))
|
self.logger.error('====-< Shortening too long PS {}name: {} -> {}'.format(fam, n, new_n))
|
||||||
return new_n
|
return new_n
|
||||||
|
|
||||||
def _shortened_name(self):
|
def _shortened_name(self):
|
||||||
@ -46,12 +47,8 @@ class FontnameParser:
|
|||||||
if not self.use_short_families[0]:
|
if not self.use_short_families[0]:
|
||||||
return (self.basename, self.rest)
|
return (self.basename, self.rest)
|
||||||
else:
|
else:
|
||||||
return (FontnameTools.concat(self.basename, self.rest).replace(' ', ''), '')
|
rest = self.rest.replace('Oblique', 'Obl')
|
||||||
|
return (FontnameTools.concat(self.basename, rest).replace(' ', ''), '')
|
||||||
def set_for_windows(self, for_windows):
|
|
||||||
"""Create slightly different names, suitable for Windows use"""
|
|
||||||
self.for_windows = for_windows
|
|
||||||
return self
|
|
||||||
|
|
||||||
def set_keep_regular_in_family(self, keep):
|
def set_keep_regular_in_family(self, keep):
|
||||||
"""Familyname may contain 'Regular' where it should normally be suppressed"""
|
"""Familyname may contain 'Regular' where it should normally be suppressed"""
|
||||||
@ -61,43 +58,20 @@ class FontnameParser:
|
|||||||
"""Suppress ID16/17 if it is identical to ID1/2 (True is default)"""
|
"""Suppress ID16/17 if it is identical to ID1/2 (True is default)"""
|
||||||
self.suppress_preferred_if_identical = suppress
|
self.suppress_preferred_if_identical = suppress
|
||||||
|
|
||||||
def inject_suffix(self, fullname, fontname, family):
|
def inject_suffix(self, family, ps_fontname, short_family):
|
||||||
"""Add a custom additonal string that shows up in the resulting names"""
|
"""Add a custom additonal string that shows up in the resulting names"""
|
||||||
self.fullname_suff = fullname.strip()
|
|
||||||
self.fontname_suff = fontname.replace(' ', '')
|
|
||||||
self.family_suff = family.strip()
|
self.family_suff = family.strip()
|
||||||
|
self.ps_fontname_suff = ps_fontname.replace(' ', '')
|
||||||
|
self.short_family_suff = short_family.strip()
|
||||||
return self
|
return self
|
||||||
# font-patcher behavior:
|
|
||||||
# verboseSuff = "Nerd Font"
|
|
||||||
# shortSuff = win ? "NF" : "Nerd Font"
|
|
||||||
# verboseSuff += "Plus Font Awesome"
|
|
||||||
# shortSuff += "A"
|
|
||||||
# OR when complete:
|
|
||||||
# shortSuff = "Nerd Font Complete"
|
|
||||||
# verboseSuff = "Nerd Font Complete"
|
|
||||||
# AND
|
|
||||||
# shortSuff += "M"
|
|
||||||
# verboseSuff += "Mono"
|
|
||||||
#
|
|
||||||
# fullname += verboseSuff
|
|
||||||
# fontname += shortSuff
|
|
||||||
# if win familyname += "NF"
|
|
||||||
# else familyname += "Nerd Font"
|
|
||||||
# if win fullname += "Windows Compatible"
|
|
||||||
# if !win familyname += "Mono"
|
|
||||||
#
|
|
||||||
# THUS:
|
|
||||||
# fontname => shortSuff
|
|
||||||
# fullname => verboseSuff {{ we do the following already: }} + win ? "Windows Compatible" : ""
|
|
||||||
# family => win ? "NF" : "Nerd Font" + mono ? "Mono" : ""
|
|
||||||
|
|
||||||
def enable_short_families(self, camelcase_name, prefix):
|
def enable_short_families(self, camelcase_name, prefix, aggressive):
|
||||||
"""Enable short styles in Family when (original) font name starts with prefix; enable CamelCase basename in (Typog.) Family"""
|
"""Enable short styles in Family when (original) font name starts with prefix; enable CamelCase basename in (Typog.) Family"""
|
||||||
# camelcase_name is boolean
|
# camelcase_name is boolean
|
||||||
# prefix is either a string or False
|
# prefix is either a string or False/True
|
||||||
if prefix:
|
if isinstance(prefix, str):
|
||||||
prefix = self._basename.startswith(prefix)
|
prefix = self._basename.startswith(prefix)
|
||||||
self.use_short_families = ( camelcase_name, prefix )
|
self.use_short_families = ( camelcase_name, prefix, aggressive )
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_name_substitution_table(self, table):
|
def add_name_substitution_table(self, table):
|
||||||
@ -107,18 +81,17 @@ class FontnameParser:
|
|||||||
self.name_subst = table
|
self.name_subst = table
|
||||||
self.basename = self._basename
|
self.basename = self._basename
|
||||||
self.rest = self._rest
|
self.rest = self._rest
|
||||||
base_and_rest = self._basename + (' ' + self._rest if len(self._rest) else '')
|
|
||||||
for regex, replacement in self.name_subst:
|
for regex, replacement in self.name_subst:
|
||||||
|
base_and_rest = self.basename + (' ' + self.rest if len(self.rest) else '')
|
||||||
m = re.match(regex, base_and_rest, re.IGNORECASE)
|
m = re.match(regex, base_and_rest, re.IGNORECASE)
|
||||||
if not m:
|
if not m:
|
||||||
continue
|
continue
|
||||||
i = len(self._basename) - len(m.group(0))
|
i = len(self.basename) - len(m.group(0))
|
||||||
if i < 0:
|
if i < 0:
|
||||||
self.basename = m.expand(replacement)
|
self.basename = m.expand(replacement).rstrip()
|
||||||
self.rest = self._rest[-(i+1):].lstrip()
|
self.rest = self.rest[-(i+1):].lstrip()
|
||||||
else:
|
else:
|
||||||
self.basename = m.expand(replacement) + self._basename[len(m.group(0)):]
|
self.basename = m.expand(replacement) + self.basename[len(m.group(0)):]
|
||||||
break
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def drop_for_powerline(self):
|
def drop_for_powerline(self):
|
||||||
@ -157,10 +130,6 @@ class FontnameParser:
|
|||||||
|
|
||||||
def fullname(self):
|
def fullname(self):
|
||||||
"""Get the SFNT Fullname (ID 4)"""
|
"""Get the SFNT Fullname (ID 4)"""
|
||||||
if self.for_windows:
|
|
||||||
win = 'Windows Compatible'
|
|
||||||
else:
|
|
||||||
win = ''
|
|
||||||
styles = self.style_token
|
styles = self.style_token
|
||||||
weights = self.weight_token
|
weights = self.weight_token
|
||||||
if self.keep_regular_in_family == None:
|
if self.keep_regular_in_family == None:
|
||||||
@ -174,41 +143,48 @@ class FontnameParser:
|
|||||||
styles.remove('Regular')
|
styles.remove('Regular')
|
||||||
# For naming purposes we want Oblique to be part of the styles
|
# For naming purposes we want Oblique to be part of the styles
|
||||||
(weights, styles) = FontnameTools.make_oblique_style(weights, styles)
|
(weights, styles) = FontnameTools.make_oblique_style(weights, styles)
|
||||||
return FontnameTools.concat(self.basename, self.rest, self.other_token, self.fullname_suff, win, weights, styles)
|
(name, rest) = self._shortened_name()
|
||||||
|
if self.use_short_families[1]:
|
||||||
|
[ weights, styles ] = FontnameTools.short_styles([ weights, styles ], self.use_short_families[2])
|
||||||
|
return FontnameTools.concat(name, rest, self.other_token, self.short_family_suff, weights, styles)
|
||||||
|
|
||||||
def psname(self):
|
def psname(self):
|
||||||
"""Get the SFNT PostScriptName (ID 6)"""
|
"""Get the SFNT PostScriptName (ID 6)"""
|
||||||
# This is almost self.family() + '-' + self.subfamily() but without short styles
|
# This is almost self.family() + '-' + self.subfamily()
|
||||||
fam = FontnameTools.camel_casify(FontnameTools.concat(self.basename, self.rest, self.other_token, self.fontname_suff))
|
(name, rest) = self._shortened_name()
|
||||||
sub = FontnameTools.camel_casify(FontnameTools.concat(self.weight_token, self.style_token))
|
styles = self.style_token
|
||||||
|
weights = self.weight_token
|
||||||
|
if self.use_short_families[1]:
|
||||||
|
styles = FontnameTools.short_styles(styles, self.use_short_families[2])
|
||||||
|
weights = FontnameTools.short_styles(weights, self.use_short_families[2])
|
||||||
|
fam = FontnameTools.camel_casify(FontnameTools.concat(name, rest, self.other_token, self.ps_fontname_suff))
|
||||||
|
sub = FontnameTools.camel_casify(FontnameTools.concat(weights, styles))
|
||||||
if len(sub) > 0:
|
if len(sub) > 0:
|
||||||
sub = '-' + sub
|
sub = '-' + sub
|
||||||
fam = FontnameTools.postscript_char_filter(fam)
|
fam = FontnameTools.postscript_char_filter(fam)
|
||||||
sub = FontnameTools.postscript_char_filter(sub)
|
sub = FontnameTools.postscript_char_filter(sub)
|
||||||
# The name string must be no longer than 63 characters
|
return self._make_ps_name(fam + sub, False)
|
||||||
if len(fam) + len(sub) > 63:
|
|
||||||
print('Shortening too long PostScriptName')
|
|
||||||
fam = fam[:(63 - len(sub))]
|
|
||||||
return fam + sub
|
|
||||||
|
|
||||||
def preferred_family(self):
|
def preferred_family(self):
|
||||||
"""Get the SFNT Preferred Familyname (ID 16)"""
|
"""Get the SFNT Preferred Familyname (ID 16)"""
|
||||||
if self.suppress_preferred_if_identical and len(self.weight_token) == 0:
|
(name, rest) = self._shortened_name()
|
||||||
|
pfn = FontnameTools.concat(name, rest, self.other_token, self.family_suff)
|
||||||
|
if self.suppress_preferred_if_identical and pfn == self.family():
|
||||||
# Do not set if identical to ID 1
|
# Do not set if identical to ID 1
|
||||||
return ''
|
return ''
|
||||||
(name, rest) = self._shortened_name()
|
return pfn
|
||||||
return FontnameTools.concat(name, rest, self.other_token, self.family_suff)
|
|
||||||
|
|
||||||
def preferred_styles(self):
|
def preferred_styles(self):
|
||||||
"""Get the SFNT Preferred Styles (ID 17)"""
|
"""Get the SFNT Preferred Styles (ID 17)"""
|
||||||
styles = self.style_token
|
styles = self.style_token
|
||||||
weights = self.weight_token
|
weights = self.weight_token
|
||||||
if self.suppress_preferred_if_identical and len(weights) == 0:
|
|
||||||
# Do not set if identical to ID 2
|
|
||||||
return ''
|
|
||||||
# For naming purposes we want Oblique to be part of the styles
|
# For naming purposes we want Oblique to be part of the styles
|
||||||
(weights, styles) = FontnameTools.make_oblique_style(weights, styles)
|
(weights, styles) = FontnameTools.make_oblique_style(weights, styles)
|
||||||
return FontnameTools.concat(weights, styles)
|
pfs = FontnameTools.concat(weights, styles)
|
||||||
|
if self.suppress_preferred_if_identical and pfs == self.subfamily():
|
||||||
|
# Do not set if identical to ID 2
|
||||||
|
return ''
|
||||||
|
return pfs
|
||||||
|
|
||||||
def family(self):
|
def family(self):
|
||||||
"""Get the SFNT Familyname (ID 1)"""
|
"""Get the SFNT Familyname (ID 1)"""
|
||||||
@ -216,10 +192,10 @@ class FontnameParser:
|
|||||||
(name, rest) = self._shortened_name()
|
(name, rest) = self._shortened_name()
|
||||||
other = self.other_token
|
other = self.other_token
|
||||||
weight = self.weight_token
|
weight = self.weight_token
|
||||||
|
aggressive = self.use_short_families[2]
|
||||||
if self.use_short_families[1]:
|
if self.use_short_families[1]:
|
||||||
other = FontnameTools.short_styles(other)
|
[ other, weight ] = FontnameTools.short_styles([ other, weight ], aggressive)
|
||||||
weight = FontnameTools.short_styles(weight)
|
return FontnameTools.concat(name, rest, other, self.short_family_suff, weight)
|
||||||
return FontnameTools.concat(name, rest, other, self.family_suff, weight)
|
|
||||||
|
|
||||||
def subfamily(self):
|
def subfamily(self):
|
||||||
"""Get the SFNT SubFamily (ID 2)"""
|
"""Get the SFNT SubFamily (ID 2)"""
|
||||||
@ -233,15 +209,10 @@ class FontnameParser:
|
|||||||
|
|
||||||
def ps_familyname(self):
|
def ps_familyname(self):
|
||||||
"""Get the PS Familyname"""
|
"""Get the PS Familyname"""
|
||||||
return self._make_ps_name(self.family(), True)
|
fam = self.preferred_family()
|
||||||
|
if len(fam) < 1:
|
||||||
def ps_fontname(self):
|
fam = self.family()
|
||||||
"""Get the PS fontname"""
|
return self._make_ps_name(fam, True)
|
||||||
# This Adobe restriction is classically ignored
|
|
||||||
# if len(n) > 29:
|
|
||||||
# print('Shortening too long PS fontname')
|
|
||||||
# return n[:29]
|
|
||||||
return self._make_ps_name(self.psname(), False)
|
|
||||||
|
|
||||||
def macstyle(self, style):
|
def macstyle(self, style):
|
||||||
"""Modify a given macStyle value for current name, just bits 0 and 1 touched"""
|
"""Modify a given macStyle value for current name, just bits 0 and 1 touched"""
|
||||||
@ -267,9 +238,18 @@ class FontnameParser:
|
|||||||
b |= WWS # We assert this by our naming process
|
b |= WWS # We assert this by our naming process
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
def checklen(self, max_len, entry_id, name):
|
||||||
|
"""Check the length of a name string and report violations"""
|
||||||
|
if len(name) <= max_len:
|
||||||
|
self.logger.debug('=====> {:18} ok ({:2} <={:2}): {}'.format(entry_id, len(name), max_len, name))
|
||||||
|
else:
|
||||||
|
self.logger.error('====-< {:18} too long ({:2} > {:2}): {}'.format(entry_id, len(name), max_len, name))
|
||||||
|
return name
|
||||||
|
|
||||||
def rename_font(self, font):
|
def rename_font(self, font):
|
||||||
"""Rename the font to include all information we found (font is fontforge font object)"""
|
"""Rename the font to include all information we found (font is fontforge font object)"""
|
||||||
font.fontname = self.ps_fontname()
|
font.fondname = None
|
||||||
|
font.fontname = self.psname()
|
||||||
font.fullname = self.fullname()
|
font.fullname = self.fullname()
|
||||||
font.familyname = self.ps_familyname()
|
font.familyname = self.ps_familyname()
|
||||||
|
|
||||||
@ -299,27 +279,32 @@ class FontnameParser:
|
|||||||
# and it is actually embedded as empty string, but empty strings are not
|
# and it is actually embedded as empty string, but empty strings are not
|
||||||
# shown if you query the sfnt_names *rolleyes*
|
# shown if you query the sfnt_names *rolleyes*
|
||||||
|
|
||||||
|
version_tag = ''
|
||||||
sfnt_list = []
|
sfnt_list = []
|
||||||
TO_DEL = ['Family', 'SubFamily', 'Fullname', 'Postscriptname', 'Preferred Family',
|
TO_DEL = ['Family', 'SubFamily', 'Fullname', 'PostScriptName', 'Preferred Family',
|
||||||
'Preferred Styles', 'Compatible Full', 'WWS Family', 'WWS Subfamily']
|
'Preferred Styles', 'Compatible Full', 'WWS Family', 'WWS Subfamily',
|
||||||
|
'UniqueID', 'CID findfont Name']
|
||||||
# Remove these entries in all languages and add (at least the vital ones) some
|
# Remove these entries in all languages and add (at least the vital ones) some
|
||||||
# back, but only as 'English (US)'. This makes sure we do not leave contradicting
|
# back, but only as 'English (US)'. This makes sure we do not leave contradicting
|
||||||
# names over different languages.
|
# names over different languages.
|
||||||
for l, k, v in list(font.sfnt_names):
|
for l, k, v in list(font.sfnt_names):
|
||||||
if not k in TO_DEL:
|
if not k in TO_DEL:
|
||||||
sfnt_list += [( l, k, v )]
|
sfnt_list += [( l, k, v )]
|
||||||
|
if k == 'Version' and l == 'English (US)':
|
||||||
|
version_tag = ' ' + v.split()[-1]
|
||||||
|
|
||||||
sfnt_list += [( 'English (US)', 'Family', self.family() )]
|
sfnt_list += [( 'English (US)', 'Family', self.checklen(31, 'Family (ID 1)', self.family()) )] # 1
|
||||||
sfnt_list += [( 'English (US)', 'SubFamily', self.subfamily() )]
|
sfnt_list += [( 'English (US)', 'SubFamily', self.checklen(31, 'SubFamily (ID 2)', self.subfamily()) )] # 2
|
||||||
sfnt_list += [( 'English (US)', 'Fullname', self.fullname() )]
|
sfnt_list += [( 'English (US)', 'UniqueID', self.fullname() + version_tag )] # 3
|
||||||
sfnt_list += [( 'English (US)', 'PostScriptName', self.psname() )]
|
sfnt_list += [( 'English (US)', 'Fullname', self.checklen(63, 'Fullname (ID 4)', self.fullname()) )] # 4
|
||||||
|
sfnt_list += [( 'English (US)', 'PostScriptName', self.checklen(63, 'PSN (ID 6)', self.psname()) )] # 6
|
||||||
|
|
||||||
p_fam = self.preferred_family()
|
p_fam = self.preferred_family()
|
||||||
if len(p_fam):
|
if len(p_fam):
|
||||||
sfnt_list += [( 'English (US)', 'Preferred Family', p_fam )]
|
sfnt_list += [( 'English (US)', 'Preferred Family', self.checklen(31, 'PrefFamily (ID 16)', p_fam) )] # 16
|
||||||
p_sty = self.preferred_styles()
|
p_sty = self.preferred_styles()
|
||||||
if len(p_sty):
|
if len(p_sty):
|
||||||
sfnt_list += [( 'English (US)', 'Preferred Styles', p_sty )]
|
sfnt_list += [( 'English (US)', 'Preferred Styles', self.checklen(31, 'PrefStyles (ID 17)', p_sty) )] # 17
|
||||||
|
|
||||||
font.sfnt_names = tuple(sfnt_list)
|
font.sfnt_names = tuple(sfnt_list)
|
||||||
|
|
||||||
|
@ -68,7 +68,6 @@ class FontnameTools:
|
|||||||
'book': '',
|
'book': '',
|
||||||
'text': '',
|
'text': '',
|
||||||
'ce': 'CE',
|
'ce': 'CE',
|
||||||
'(ttf)': '(TTF)',
|
|
||||||
#'semibold': 'Demi',
|
#'semibold': 'Demi',
|
||||||
'ob': 'Oblique',
|
'ob': 'Oblique',
|
||||||
'it': 'Italic',
|
'it': 'Italic',
|
||||||
@ -85,27 +84,57 @@ class FontnameTools:
|
|||||||
return style_name
|
return style_name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def shorten_style_name(name):
|
def find_in_dicts(key, dicts):
|
||||||
|
"""Find an entry in a list of dicts, return entry and in which list it was"""
|
||||||
|
for i, d in enumerate(dicts):
|
||||||
|
if key in d:
|
||||||
|
return ( d[key], i )
|
||||||
|
return (None, 0)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_shorten_form_idx(aggressive, prefix, form_if_prefixed):
|
||||||
|
"""Get the tuple index of known_* data tables"""
|
||||||
|
if aggressive:
|
||||||
|
return 0
|
||||||
|
if len(prefix):
|
||||||
|
return form_if_prefixed
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def shorten_style_name(name, aggressive):
|
||||||
"""Substitude some known styles to short form"""
|
"""Substitude some known styles to short form"""
|
||||||
known_names = {
|
# If aggressive is False create the mild short form
|
||||||
# Chiefly from Noto
|
# aggressive == True: Always use first form of everything
|
||||||
'SemiCondensed': 'SemCond',
|
# aggressive == False:
|
||||||
'Condensed': 'Cond',
|
# - has no modifier: use the second form
|
||||||
'ExtraCondensed': 'ExtCond',
|
# - has modifier: use second form of mod plus first form of weights2
|
||||||
'SemiBold': 'SemBd',
|
# - has modifier: use second form of mod plus second form of widths
|
||||||
'ExtraBold': 'ExtBd',
|
name_rest = name
|
||||||
'Medium': 'Med',
|
name_pre = ''
|
||||||
'ExtraLight': 'ExtLt',
|
form = FontnameTools.get_shorten_form_idx(aggressive, '', 0)
|
||||||
'Black': 'Blk',
|
for mod in FontnameTools.known_modifiers:
|
||||||
}
|
if name.startswith(mod) and len(name) > len(mod): # Second condition specifically for 'Demi'
|
||||||
if name in known_names:
|
name_pre = FontnameTools.known_modifiers[mod][form]
|
||||||
return known_names[name]
|
name_rest = name[len(mod):]
|
||||||
|
break
|
||||||
|
subst, i = FontnameTools.find_in_dicts(name_rest, [ FontnameTools.known_weights2, FontnameTools.known_widths ])
|
||||||
|
form = FontnameTools.get_shorten_form_idx(aggressive, name_pre, i)
|
||||||
|
if isinstance(subst, tuple):
|
||||||
|
return name_pre + subst[form]
|
||||||
|
if not len(name_pre):
|
||||||
|
# The following sets do not allow modifiers
|
||||||
|
subst, _ = FontnameTools.find_in_dicts(name_rest, [ FontnameTools.known_weights1, FontnameTools.known_slopes ])
|
||||||
|
if isinstance(subst, tuple):
|
||||||
|
return subst[form]
|
||||||
return name
|
return name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def short_styles(styles):
|
def short_styles(lists, aggressive):
|
||||||
"""Shorten all style names in a list"""
|
"""Shorten all style names in a list or a list of lists"""
|
||||||
return list(map(FontnameTools.shorten_style_name, styles))
|
if not len(lists) or not isinstance(lists[0], list):
|
||||||
|
return list(map(lambda x: FontnameTools.shorten_style_name(x, aggressive), lists))
|
||||||
|
return [ list(map(lambda x: FontnameTools.shorten_style_name(x, aggressive), styles)) for styles in lists ]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_oblique_style(weights, styles):
|
def make_oblique_style(weights, styles):
|
||||||
"""Move "Oblique" from weights to styles for font naming purposes"""
|
"""Move "Oblique" from weights to styles for font naming purposes"""
|
||||||
@ -174,12 +203,77 @@ class FontnameTools:
|
|||||||
( '(a)nka/(c)oder', r'\1na\2onder' ),
|
( '(a)nka/(c)oder', r'\1na\2onder' ),
|
||||||
( '(c)ascadia( ?)(c)ode', r'\1askaydia\2\3ove' ),
|
( '(c)ascadia( ?)(c)ode', r'\1askaydia\2\3ove' ),
|
||||||
( '(c)ascadia( ?)(m)ono', r'\1askaydia\2\3ono' ),
|
( '(c)ascadia( ?)(m)ono', r'\1askaydia\2\3ono' ),
|
||||||
( '(m)plus', r'\1+'), # Added this, because they use a plus symbol :->
|
( '(m)( ?)plus', r'\1+'), # Added this, because they use a plus symbol :->
|
||||||
( 'Gohufont', r'GohuFont'), # Correct to CamelCase
|
( 'Gohufont', r'GohuFont'), # Correct to CamelCase
|
||||||
# Noone cares that font names starting with a digit are forbidden:
|
# Noone cares that font names starting with a digit are forbidden:
|
||||||
( 'IBM 3270', r'3270'), # for historical reasons and 'IBM' is a TM or something
|
( 'IBM 3270', r'3270'), # for historical reasons and 'IBM' is a TM or something
|
||||||
|
# Some name parts that are too long for us
|
||||||
|
( '(.*sans ?m)ono', r'\1'), # Various SomenameSansMono fonts
|
||||||
|
( '(.*code ?lat)in Expanded', r'\1X'), # for 'M PLUS Code Latin Expanded'
|
||||||
|
( '(.*code ?lat)in', r'\1'), # for 'M PLUS Code Latin'
|
||||||
|
( '(b)ig( ?)(b)lue( ?)(t)erminal', r'\1ig\3lue\5erm'), # Shorten BigBlueTerminal
|
||||||
|
( '(.*)437TT', r'\g<1>437'), # Shorten BigBlueTerminal 437 TT even further
|
||||||
|
( '(.*dyslexic ?alt)a', r'\1'), # Open Dyslexic Alta -> Open Dyslexic Alt
|
||||||
|
( '(.*dyslexic ?m)ono', r'\1'), # Open Dyslexic Mono -> Open Dyslexic M
|
||||||
|
( '(overpass ?m)ono', r'\1'), # Overpass Mono -> Overpass M
|
||||||
|
( '(proggyclean) ?tt', r'\1'), # Remove TT from ProggyClean
|
||||||
|
( '(terminess) ?\(ttf\)', r'\1'), # Remove TTF from Terminus (after renamed to Terminess)
|
||||||
|
( '(im ?writing ?q)uattro', r'\1uat'), # Rename iM Writing Quattro to Quat
|
||||||
|
( '(im ?writing ?(mono|duo|quat)) ?s', r'\1'), # Remove S from all iM Writing styles
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# From https://adobe-type-tools.github.io/font-tech-notes/pdfs/5088.FontNames.pdf
|
||||||
|
# The first short variant is from the linked table.
|
||||||
|
# The second (longer) short variant is from diverse fonts like Noto.
|
||||||
|
# We can
|
||||||
|
# - use the long form
|
||||||
|
# - use the very short form (first)
|
||||||
|
# - use mild short form:
|
||||||
|
# - has no modifier: use the second form
|
||||||
|
# - has modifier: use second form of mod plus first form of weights2
|
||||||
|
# - has modifier: use second form of mod plus second form of widths
|
||||||
|
# This is encoded in get_shorten_form_idx()
|
||||||
|
known_weights1 = { # can not take modifiers
|
||||||
|
'Medium': ('Md', 'Med'),
|
||||||
|
'Nord': ('Nd', 'Nord'),
|
||||||
|
'Book': ('Bk', 'Book'),
|
||||||
|
'Poster': ('Po', 'Poster'),
|
||||||
|
'Demi': ('Dm', 'Demi'), # Demi is sometimes used as a weight, sometimes as a modifier
|
||||||
|
'Regular': ('Rg', 'Reg'),
|
||||||
|
'Display': ('DS', 'Disp'),
|
||||||
|
'Super': ('Su', 'Sup'),
|
||||||
|
'Retina': ('Rt', 'Ret'),
|
||||||
|
}
|
||||||
|
known_weights2 = { # can take modifiers
|
||||||
|
'Black': ('Blk', 'Black'),
|
||||||
|
'Bold': ('Bd', 'Bold'),
|
||||||
|
'Heavy': ('Hv', 'Heavy'),
|
||||||
|
'Thin': ('Th', 'Thin'),
|
||||||
|
'Light': ('Lt', 'Light'),
|
||||||
|
' ': (), # Just for CodeClimate :-/
|
||||||
|
}
|
||||||
|
known_widths = { # can take modifiers
|
||||||
|
'Compressed': ('Cm', 'Comp'),
|
||||||
|
'Extended': ('Ex', 'Extd'),
|
||||||
|
'Condensed': ('Cn', 'Cond'),
|
||||||
|
'Narrow': ('Nr', 'Narrow'),
|
||||||
|
'Compact': ('Ct', 'Compact'),
|
||||||
|
}
|
||||||
|
known_slopes = { # can not take modifiers
|
||||||
|
'Inclined': ('Ic', 'Incl'),
|
||||||
|
'Oblique': ('Obl', 'Obl'),
|
||||||
|
'Italic': ('It', 'Italic'),
|
||||||
|
'Upright': ('Up', 'Uprght'),
|
||||||
|
'Kursiv': ('Ks', 'Kurs'),
|
||||||
|
'Sloped': ('Sl', 'Slop'),
|
||||||
|
}
|
||||||
|
known_modifiers = {
|
||||||
|
'Demi': ('Dm', 'Dem'),
|
||||||
|
'Ultra': ('Ult', 'Ult'),
|
||||||
|
'Semi': ('Sm', 'Sem'),
|
||||||
|
'Extra': ('X', 'Ext'),
|
||||||
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_keep_regular(basename):
|
def is_keep_regular(basename):
|
||||||
"""This has been decided by the font designers, we need to mimic that (for comparison purposes)"""
|
"""This has been decided by the font designers, we need to mimic that (for comparison purposes)"""
|
||||||
@ -241,18 +335,18 @@ class FontnameTools:
|
|||||||
# Weights end up as Typographic Family parts ('after the dash')
|
# Weights end up as Typographic Family parts ('after the dash')
|
||||||
# Styles end up as Family parts (for classic grouping of four)
|
# Styles end up as Family parts (for classic grouping of four)
|
||||||
# Others also end up in Typographic Family ('before the dash')
|
# Others also end up in Typographic Family ('before the dash')
|
||||||
weights = [ 'Thin', 'Light', 'ExtraLight', 'SemiBold', 'Demi',
|
weights = [ m + s
|
||||||
'SemiLight', 'Medium', 'Black', 'ExtraBold', 'Heavy',
|
for s in list(FontnameTools.known_weights2) + list(FontnameTools.known_widths)
|
||||||
'Oblique', 'Condensed', 'SemiCondensed', 'ExtraCondensed',
|
for m in list(FontnameTools.known_modifiers) + [''] if m != s
|
||||||
'Narrow', 'SemiNarrow', 'Retina', ]
|
] + list(FontnameTools.known_weights1)
|
||||||
styles = [ 'Bold', 'Italic', 'Regular', 'Normal', ]
|
styles = [ 'Bold', 'Italic', 'Regular', 'Normal', ]
|
||||||
|
weights = [ w for w in weights if w not in styles ]
|
||||||
# Some font specialities:
|
# Some font specialities:
|
||||||
other = [
|
other = [
|
||||||
'-', 'Book', 'For', 'Powerline',
|
'-', 'Book', 'For', 'Powerline',
|
||||||
'Text', # Plex
|
'Text', # Plex
|
||||||
'IIx', # Profont IIx
|
'IIx', # Profont IIx
|
||||||
'LGC', # Inconsolata LGC
|
'LGC', # Inconsolata LGC
|
||||||
r'\(TTF\)', # Terminus (TTF)
|
|
||||||
r'\bCE\b', # ProggycleanTT CE
|
r'\bCE\b', # ProggycleanTT CE
|
||||||
r'[12][cmp]n?', # MPlus
|
r'[12][cmp]n?', # MPlus
|
||||||
r'(?:uni-)?1[14]', # GohuFont uni
|
r'(?:uni-)?1[14]', # GohuFont uni
|
||||||
|
@ -54,105 +54,8 @@ work as it always did.
|
|||||||
|
|
||||||
### The Tests
|
### The Tests
|
||||||
|
|
||||||
In this directory there are two tests.
|
In this directory were two tests. If interested you need to go back in the git history.
|
||||||
|
They are not needed anymore.
|
||||||
1. The first test checks the basics of the algorithm. It takes the filenames of all fonts in
|
|
||||||
`src/unpatched-fonts/`, then it calculates the naming and compares it to the original
|
|
||||||
naming in the font files. Ideally they would be equal.
|
|
||||||
2. The second test does a 'production run'. It patches each font in `src/unpatched-fonts/`
|
|
||||||
and patches it two times: Once without `--makegroups` and once with. Then it compares the
|
|
||||||
naming, and it also shows the original font naming (for comparison).
|
|
||||||
|
|
||||||
All tests base on these assumptions
|
|
||||||
|
|
||||||
* Fullname must be roughly equal
|
|
||||||
* Fontname must be roughly equal
|
|
||||||
* Familyname must roughly equal, order of all words does not matter
|
|
||||||
_(Order of words is ignored with test 2 only)_
|
|
||||||
* SubFamilyname must be equal, order of words does not matter
|
|
||||||
_(First word must be equal, order of other words is ignored with test 2 only)_
|
|
||||||
* Typographic names can be empty if the correct typographic name would be equal to the ordinary name
|
|
||||||
* Tests are done case insensitive
|
|
||||||
* Some special exemptions are made (see `lenient_cmp()` in test scripts)
|
|
||||||
|
|
||||||
#### Test 1
|
|
||||||
|
|
||||||
`fontforge name_parser_test1 ../../../src/unpatched-fonts/**/*.[ot]tf 2>/dev/null`
|
|
||||||
|
|
||||||
This test takes the filename of a font, parses it and generates names from it. Then the actual
|
|
||||||
font is opened and the generated names are compared with the stored names. This test is used
|
|
||||||
to test the algorithm itself. Of course no SIL table is active as we want to preserve the original
|
|
||||||
names.
|
|
||||||
|
|
||||||
The output shows all the names, always two lines: first the generated names, then the readout
|
|
||||||
names. If there are differences the generated names are tagged with `+` and the readout ones
|
|
||||||
with `-`. If there are differences the actually different name part is marked with an `X`.
|
|
||||||
|
|
||||||
The differences have reasons, and there is a file with textual explanations for them. So far
|
|
||||||
all differences are 'ok'. A new run of the script will compare all differences with the stored
|
|
||||||
ones and alert the user if a new difference is detected (or a difference vanished). In this
|
|
||||||
way changes of the algorithm can be tested with a wide base of inputs.
|
|
||||||
|
|
||||||
#### Test 2
|
|
||||||
|
|
||||||
`fontforge name_parser_test2 ../../../src/unpatched-fonts/**/*.[ot]tf 2>/dev/null`
|
|
||||||
|
|
||||||
This test compares actually patched fonts. Every font in `src/unpatched-fonts/` is patched two
|
|
||||||
times: First with the 'old/classic' `font-patcher` naming, and second with the new naming
|
|
||||||
algorithm in action (by specifying `--makegroups`). Again the name parts are compared with some
|
|
||||||
lenience and an output generated like test 1 does.
|
|
||||||
|
|
||||||
Also again a file with known differences (with explanations) is read, and any new or vanished
|
|
||||||
differences are reported. In the report an additional line is given, tagged with `>`, that
|
|
||||||
contains the names of the original font, for human interpretation (often the reason
|
|
||||||
for a difference is obvious, because the classic `font-patcher` dropped information.
|
|
||||||
|
|
||||||
_Note: Fonts `NotoColorEmoji` and `Lilex-VF` are not patchable, and thus ignored_
|
|
||||||
_Note: Fonts `iosevka-heavyoblique`, `iosevka-term-heavyoblique`, `iosevka-mediumoblique` crash my machine and are ignored_
|
|
||||||
|
|
||||||
### Differences
|
|
||||||
|
|
||||||
The naming of the patched fonts, if `--makegroups` is applied, will be different. Of course, that is the goal.
|
|
||||||
What are the differences in particular:
|
|
||||||
|
|
||||||
* `Nerd Font` is not added in the end, but after the extended base name before the style
|
|
||||||
* The SubFamily contains only 4 Styles max: Regular, Bold, Italic, Bold-Italic
|
|
||||||
* The Noto fonts retain their abbreviated style names in the Family information
|
|
||||||
* `Nerd Font Mono` fonts get a `M` in windows mode (I believe that has been left out accidentally before)
|
|
||||||
|
|
||||||
Apart from these general things, all changes are documented in detail in the `name_parser_test2` issues file.
|
|
||||||
Here is an overview over all the things that get renamed and why:
|
|
||||||
|
|
||||||
| Occurences | Description |
|
|
||||||
|------------|-------------|
|
|
||||||
| 511 | Add weight/style to family |
|
|
||||||
| 43 | The fonts name is M+ not Mplus |
|
|
||||||
| 36 | Drop unneeded Typogr.Family/Typogr.Style |
|
|
||||||
| 26 | 'Term' is missing from Family |
|
|
||||||
| 22 | Change regular-equivalent name to Regular |
|
|
||||||
| 19 | Put Oblique into own SubFamily (and mark it as italic) |
|
|
||||||
| 5 | Drop Regular from Style |
|
|
||||||
| 4 | We handle (TTF) as sub-name |
|
|
||||||
| 4 | Fullname has been missing 'Nerd Font' |
|
|
||||||
| 4 | Bold / Bold-Italic are just a styles of Regular |
|
|
||||||
| 2 | Original font broken (Light in Family) |
|
|
||||||
| 2 | Classify Medium as own weigt and not Bold |
|
|
||||||
| 2 | Bold and Italic are styles of a basefont |
|
|
||||||
| 1 | Weight Condensed does not belong to base name |
|
|
||||||
| 1 | Use only Regular/Bold/Italic in SubFamily |
|
|
||||||
| 1 | Handle Retina as Weight and not Style |
|
|
||||||
| 1 | Do not call Semibold Light-Bold |
|
|
||||||
|
|
||||||
From the count we see that almost all fonts are affected by incorrect Family naming.
|
|
||||||
|
|
||||||
### Further steps
|
|
||||||
|
|
||||||
One can examine all the (current) naming differences in the `name_parser_test2.known_issues`
|
|
||||||
file. The Explanation is followed by three lines of names: source-file, patched-with-makegroups,
|
|
||||||
and patched-classic.
|
|
||||||
|
|
||||||
The Explanation sorts most differences into common groups. This helps to weed out
|
|
||||||
explanations that might do not need much attention.
|
|
||||||
|
|
||||||
### Helper scripts
|
### Helper scripts
|
||||||
|
|
||||||
@ -166,30 +69,3 @@ way:
|
|||||||
* `query_version` `font_name`
|
* `query_version` `font_name`
|
||||||
|
|
||||||
They can be invoked like this `$ fontforge query_sfnt foo.ttf`.
|
They can be invoked like this `$ fontforge query_sfnt foo.ttf`.
|
||||||
|
|
||||||
### Appendix: The `name_parser_test*.known_issues` files
|
|
||||||
|
|
||||||
All differences of 'old' to 'new' naming (if not one of the very general kind like resorting of
|
|
||||||
the words) are documented in the `known_issues` files. For each difference a reason is given.
|
|
||||||
|
|
||||||
The files consist of entries that spans 3 (for test 1) or 4 (for test 2) lines.
|
|
||||||
| Line starts with | Contents |
|
|
||||||
|------------------|----------|
|
|
||||||
| # | Reson for the difference (or `AUTOGENERATED`) |
|
|
||||||
| > | Naming fo the original/source font (only test 2) |
|
|
||||||
| + | Naming with `--makegroups` (new naming) |
|
|
||||||
| - | Naming classically generated by font-patcher |
|
|
||||||
|
|
||||||
After any test run a `known_issues.new` file is generated. It contains all the issues
|
|
||||||
from the `known_issues` file that were detected. Original issues that are not
|
|
||||||
existing anymore are at the bottom of the new file, clearly marked as such. If new
|
|
||||||
(previously unexplained) issues were detected they show up with the `AUTOGENERATED`
|
|
||||||
reason.
|
|
||||||
|
|
||||||
After adding new fonts or replacing font files the test can be rerun. If there are issues
|
|
||||||
in the `.new` file they should be documented there, and the `.new` file replace the
|
|
||||||
original `known_issues` file (after removing possible 'obsolete' issues that are listed in
|
|
||||||
the bottom of the new file).
|
|
||||||
|
|
||||||
In this way one can tweak the parser code and compare very easily what a change
|
|
||||||
means for all the fonts, which will break or be repaired.
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
cat name_parser_test2.known_issues | grep '####' | sed -E 's/#### //;s/\] /]\n/g;s/ \[[0-9]+\]//g' | sort | uniq -c | sort -nr
|
|
||||||
|
|
||||||
511 Add weight/style to family
|
|
||||||
43 The fonts name is M+ not Mplus
|
|
||||||
36 Drop unneeded Typogr.Family/Typogr.Style
|
|
||||||
26 'Term' is missing from Family
|
|
||||||
22 Change regular-equivalent name to Regular
|
|
||||||
19 Put Oblique into own SubFamily (and mark it as italic)
|
|
||||||
5 Drop Regular from Style
|
|
||||||
4 We handle (TTF) as sub-name
|
|
||||||
4 Fullname has been missing 'Nerd Font'
|
|
||||||
4 Bold / Bold-Italic are just a styles of Regular
|
|
||||||
2 Original font broken (Light in Family)
|
|
||||||
2 Classify Medium as own weigt and not Bold
|
|
||||||
2 Bold and Italic are styles of a basefont
|
|
||||||
1 Weight Condensed does not belong to base name
|
|
||||||
1 Use only Regular/Bold/Italic in SubFamily
|
|
||||||
1 Handle Retina as Weight and not Style
|
|
||||||
1 Do not call Semibold Light-Bold
|
|
@ -1,160 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# coding=utf8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import os.path
|
|
||||||
import fontforge
|
|
||||||
from FontnameParser import FontnameParser
|
|
||||||
|
|
||||||
###### Some helpers
|
|
||||||
|
|
||||||
def get_sfnt_dict(font):
|
|
||||||
"""Extract SFNT table as nice dict"""
|
|
||||||
d = []
|
|
||||||
for i, el in enumerate(font.sfnt_names):
|
|
||||||
d += [(el[1], el[2])]
|
|
||||||
return dict(d)
|
|
||||||
|
|
||||||
def format_names(header, *stuff):
|
|
||||||
"""Unify outputs (with header)"""
|
|
||||||
f = '{:1.1}|{:50.50} |{:1.1}| {:50.50} |{:1.1}| {:30.30} |{:1.1}| {:30.30} |{:1.1}| {:30.30} |{:1.1}| {:.30}'
|
|
||||||
if header:
|
|
||||||
d = '------------------------------------------------------------'
|
|
||||||
return f.format(*stuff) + '\n' + f.format('', d, d, d, d, d, d, d, d, d, d, d)
|
|
||||||
return f.format(*stuff).rstrip()
|
|
||||||
|
|
||||||
def lenient_cmp(s1, s2):
|
|
||||||
"""Compare two font name (parts) but be a bit lenient ;->"""
|
|
||||||
# We do not care about:
|
|
||||||
# - Case
|
|
||||||
# - "Display" vs "Disp" (in Noto)
|
|
||||||
# Allow for "IBM 3278" name
|
|
||||||
s = [ s1, s2 ]
|
|
||||||
for i in range(2):
|
|
||||||
# Usually given transform from 'their' to 'our' style
|
|
||||||
s[i] = s[i].lower()
|
|
||||||
s[i] = re.sub(r'\bdisp\b', 'display', s[i]) # Noto
|
|
||||||
s[i] = s[i].replace('ibm 3270', '3270') # 3270
|
|
||||||
s[i] = s[i].replace('3270-', '3270 ') # 3270
|
|
||||||
s[i] = s[i].replace('lekton-', 'lekton ') # Lekton
|
|
||||||
s[i] = s[i].replace('semi-narrow', 'seminarrow') # 3270
|
|
||||||
s[i] = s[i].replace('bolditalic', 'bold italic')
|
|
||||||
s[i] = re.sub(r'\bfor\b', '', s[i]) # Meslo, Monofur
|
|
||||||
s[i] = re.sub(r'\bpowerline\b', '', s[i]) # Meslo, Monofur
|
|
||||||
s[i] = s[i].replace('fira mono', 'fura mono') # Obviously someone forgot to rename the fonts in Fira/
|
|
||||||
s[i] = s[i].replace('aurulentsansmono-', 'aurulent sans mono ') # Aurulent fullname oddity
|
|
||||||
s[i] = s[i].replace('mononoki-', 'mononoki ') # Mononoki has somtimes a dash
|
|
||||||
s[i] = re.sub(r'\br\b', 'regular', s[i]) # Nonstandard style in Agave
|
|
||||||
s[i] = re.sub(r'(bitstream vera sans mono.*) oblique', r'\1 italic', s[i]) # They call it Oblique but the filename says Italic
|
|
||||||
s[i] = re.sub(r'gohufont (uni-)?(11|14)', 'gohufont', s[i]) # They put the 'name' into the subfamily/weight
|
|
||||||
s[i] = s[i].replace('xltobl', 'extralight oblique') # Iosevka goes inventing names
|
|
||||||
s[i] = re.sub(r'proggyclean(?!TT)( ?)', 'proggycleantt\1', s[i]) # ProggyClean has no TT in filename
|
|
||||||
|
|
||||||
s[i] = re.sub(r' +', ' ', s[i]).strip()
|
|
||||||
return s[0] == s[1]
|
|
||||||
|
|
||||||
TEST_TABLE = [
|
|
||||||
( '(m)plus', '\\1+'),
|
|
||||||
( 'IAWriter', 'iA Writer'),
|
|
||||||
( 'IBMPlex', 'IBM Plex'),
|
|
||||||
( 'Vera', 'Bitstream Vera Sans'),
|
|
||||||
]
|
|
||||||
|
|
||||||
###### Let's go!
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print('Usage: {} font_name [font_name ...]\n'.format(sys.argv[0]))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(sys.argv[0] + '.known_issues', 'r') as f:
|
|
||||||
known_issues = f.read().splitlines()
|
|
||||||
# known_issues = [line.rstrip() for line in known_issues]
|
|
||||||
print('Found {:.0f} known issues'.format(len(known_issues) / 3)) # approx ;)
|
|
||||||
except OSError:
|
|
||||||
print('Can not open known_issues file')
|
|
||||||
known_issues = []
|
|
||||||
new_issues = open(sys.argv[0] + '.known_issues.new', 'w')
|
|
||||||
|
|
||||||
print('Examining {} font files'.format(len(sys.argv) - 1))
|
|
||||||
all_files = 0
|
|
||||||
issue_files = 0
|
|
||||||
known_files = 0
|
|
||||||
|
|
||||||
print(format_names(True, '', 'Filename', '', 'Fullname', '', 'Family', '', 'Subfamily', '', 'Typogr. Family', '', 'Typogr. Subfamily'))
|
|
||||||
|
|
||||||
for filename in sys.argv[1:]:
|
|
||||||
fullfile = os.path.basename(filename)
|
|
||||||
fname = os.path.splitext(fullfile)[0]
|
|
||||||
if fname == 'NotoColorEmoji':
|
|
||||||
continue # font is not patchable
|
|
||||||
n = FontnameParser(fname).enable_short_families(False, 'Noto').add_name_substitution_table(TEST_TABLE)
|
|
||||||
# Example for name injection:
|
|
||||||
# n.inject_suffix("Nerd Font Complete Mono", "Nerd Font Complete M", "Nerd Font Mono")
|
|
||||||
|
|
||||||
font = fontforge.open(filename, 1)
|
|
||||||
sfnt = get_sfnt_dict(font)
|
|
||||||
font.close()
|
|
||||||
all_files += 1
|
|
||||||
|
|
||||||
sfnt_full = sfnt['Fullname']
|
|
||||||
sfnt_fam = sfnt['Family']
|
|
||||||
sfnt_subfam = sfnt['SubFamily']
|
|
||||||
sfnt_pfam = sfnt['Preferred Family'] if 'Preferred Family' in sfnt else ''
|
|
||||||
sfnt_psubfam = sfnt['Preferred Styles'] if 'Preferred Styles' in sfnt else ''
|
|
||||||
|
|
||||||
t1 = not lenient_cmp(sfnt_full, n.fullname())
|
|
||||||
t2 = not lenient_cmp(sfnt_fam, n.family())
|
|
||||||
t3 = not lenient_cmp(sfnt_subfam, n.subfamily())
|
|
||||||
t4 = not lenient_cmp(sfnt_pfam, n.preferred_family())
|
|
||||||
t5 = not lenient_cmp(sfnt_psubfam, n.preferred_styles())
|
|
||||||
|
|
||||||
# Lenience: Allow for dropping unneeded prefered stuff:
|
|
||||||
# New (sub)family is same as old preferred sub(family)
|
|
||||||
if t4 and n.preferred_family() == '' and sfnt_pfam.lower() == n.family().lower():
|
|
||||||
t4 = False
|
|
||||||
if t5 and n.preferred_styles() == '' and sfnt_psubfam.lower() == n.subfamily().lower():
|
|
||||||
t5 = False
|
|
||||||
|
|
||||||
if t1 or t2 or t3 or t4 or t5:
|
|
||||||
m1 = '+'; m2 = '-'
|
|
||||||
else:
|
|
||||||
m1 = ''; m2 = ''
|
|
||||||
if not n.parse_ok:
|
|
||||||
m1 = '!'
|
|
||||||
t1_ = 'X' if t1 else ''
|
|
||||||
t2_ = 'X' if t2 else ''
|
|
||||||
t3_ = 'X' if t3 else ''
|
|
||||||
t4_ = 'X' if t4 else ''
|
|
||||||
t5_ = 'X' if t5 else ''
|
|
||||||
|
|
||||||
o1 = format_names(False, m1, fullfile, t1_, n.fullname(), t2_, n.family(), t3_, n.subfamily(), t4_, n.preferred_family(), t5_, n.preferred_styles())
|
|
||||||
o2 = format_names(False, m2, fullfile, '', sfnt_full, '', sfnt_fam, '', sfnt_subfam, '', sfnt_pfam, '', sfnt_psubfam)
|
|
||||||
|
|
||||||
if len(m1):
|
|
||||||
issue_files += 1
|
|
||||||
if not o1 in known_issues or not o2 in known_issues:
|
|
||||||
new_issues.writelines(['#### AUTOGENERATED\n', o1 + '\n', o2 + '\n'])
|
|
||||||
else:
|
|
||||||
known_files += 1
|
|
||||||
idx = known_issues.index(o1) - 1 # should be the index of the explanation line
|
|
||||||
if known_issues[idx][0] != '#':
|
|
||||||
sys.exit('Problem with known issues file, line', known_issues.index(o1))
|
|
||||||
new_issues.writelines([known_issues[idx] + '\n', o1 + '\n', o2 + '\n'])
|
|
||||||
# remove known_issue triplet
|
|
||||||
known_issues.pop(idx)
|
|
||||||
known_issues.pop(idx)
|
|
||||||
known_issues.pop(idx)
|
|
||||||
|
|
||||||
print(o1, o2, sep='\n')
|
|
||||||
|
|
||||||
print('Fonts with different name rendering: {}/{} ({}/{} are in known_issues)'.format(issue_files, all_files, known_files, issue_files))
|
|
||||||
|
|
||||||
if len(known_issues) > 0:
|
|
||||||
print('There are {} lines not needed in known_issues, appending commented out in new known_issues'.format(len(known_issues)))
|
|
||||||
new_issues.write('\n#### The following lines are not needed anymore\n\n')
|
|
||||||
for l in known_issues:
|
|
||||||
new_issues.writelines([' ', l, '\n'])
|
|
||||||
|
|
||||||
new_issues.close()
|
|
@ -1,207 +0,0 @@
|
|||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|3270Medium.otf | | 3270 Medium |X| 3270 Medium |X| Regular |X| 3270 |X| Medium
|
|
||||||
-|3270Medium.otf | | 3270-Medium | | IBM 3270 | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|3270Medium.ttf | | 3270 Medium |X| 3270 Medium |X| Regular |X| 3270 |X| Medium
|
|
||||||
-|3270Medium.ttf | | 3270-Medium | | IBM 3270 | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, obviously for them Medium is Regular
|
|
||||||
+|3270Narrow.otf | | 3270 Narrow | | 3270 Narrow |X| Regular |X| 3270 |X| Narrow
|
|
||||||
-|3270Narrow.otf | | 3270 Narrow | | IBM 3270 Narrow | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, obviously for them Medium is Regular
|
|
||||||
+|3270Narrow.ttf | | 3270 Narrow | | 3270 Narrow |X| Regular |X| 3270 |X| Narrow
|
|
||||||
-|3270Narrow.ttf | | 3270 Narrow | | IBM 3270 Narrow | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, obviously for them Medium is Regular
|
|
||||||
+|3270SemiNarrow.otf | | 3270 SemiNarrow | | 3270 SemiNarrow |X| Regular |X| 3270 |X| SemiNarrow
|
|
||||||
-|3270SemiNarrow.otf | | 3270 Semi-Narrow | | IBM 3270 Semi-Narrow | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, obviously for them Medium is Regular
|
|
||||||
+|3270SemiNarrow.ttf | | 3270 SemiNarrow | | 3270 SemiNarrow |X| Regular |X| 3270 |X| SemiNarrow
|
|
||||||
-|3270SemiNarrow.ttf | | 3270 Semi-Narrow | | IBM 3270 Semi-Narrow | | Medium | | | |
|
|
||||||
#### Drop special/unexpected name in Typographic Family
|
|
||||||
+|Anonymice Powerline.ttf | | Anonymice Powerline | | Anonymice Powerline | | Regular |X| | |
|
|
||||||
-|Anonymice Powerline.ttf | | Anonymice Powerline | | Anonymice Powerline | | Regular | | Anonymous Pro for Powerline | | Regular
|
|
||||||
#### Font file says it is italic and not oblique
|
|
||||||
+|VeraMono-Bold-Italic.ttf | | Bitstream Vera Sans Mono Bold Italic | | Bitstream Vera Sans Mono |X| Bold Italic | | | |
|
|
||||||
-|VeraMono-Bold-Italic.ttf | | Bitstream Vera Sans Mono Bold Oblique | | Bitstream Vera Sans Mono | | Bold Oblique | | | |
|
|
||||||
#### Font file says it is italic and not oblique
|
|
||||||
+|VeraMono-Italic.ttf | | Bitstream Vera Sans Mono Italic | | Bitstream Vera Sans Mono |X| Italic | | | |
|
|
||||||
-|VeraMono-Italic.ttf | | Bitstream Vera Sans Mono Oblique | | Bitstream Vera Sans Mono | | Oblique | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, Roman is usually equivalent to Regular
|
|
||||||
+|VeraMono.ttf | | Bitstream Vera Sans Mono | | Bitstream Vera Sans Mono |X| Regular | | | |
|
|
||||||
-|VeraMono.ttf | | Bitstream Vera Sans Mono | | Bitstream Vera Sans Mono | | Roman | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, Book is usually equivalent to Regular
|
|
||||||
!|DaddyTimeMono.ttf | | DaddyTimeMono | | DaddyTimeMono |X| Regular | | | |
|
|
||||||
-|DaddyTimeMono.ttf | | DaddyTimeMono | | DaddyTimeMono | | Book | | DaddyTimeMono | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|DejaVuSansMono-BoldOblique.ttf | | DejaVu Sans Mono Bold Oblique |X| DejaVu Sans Mono Oblique |X| Bold Italic |X| DejaVu Sans Mono |X| Bold Oblique
|
|
||||||
-|DejaVuSansMono-BoldOblique.ttf | | DejaVu Sans Mono Bold Oblique | | DejaVu Sans Mono | | Bold Oblique | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|DejaVuSansMono-Oblique.ttf | | DejaVu Sans Mono Oblique |X| DejaVu Sans Mono Oblique |X| Italic |X| DejaVu Sans Mono |X| Oblique
|
|
||||||
-|DejaVuSansMono-Oblique.ttf | | DejaVu Sans Mono Oblique | | DejaVu Sans Mono | | Oblique | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, Book is usually equivalent to Regular
|
|
||||||
+|DejaVuSansMono.ttf | | DejaVu Sans Mono | | DejaVu Sans Mono |X| Regular | | | |
|
|
||||||
-|DejaVuSansMono.ttf | | DejaVu Sans Mono | | DejaVu Sans Mono | | Book | | | |
|
|
||||||
#### No need to have Typographic Family/Subfamily if it is identical to normal Family/Subfamily
|
|
||||||
+|FuraMono-Bold Powerline.otf | | Fura Mono Powerline Bold | | Fura Mono Powerline | | Bold |X| | |
|
|
||||||
-|FuraMono-Bold Powerline.otf | | Fira Mono Bold for Powerline | | Fira Mono for Powerline | | Bold | | Fira Mono for Powerline | |
|
|
||||||
#### False positive, move Powerline from end to middle, Powerline will be dropped when patching anyhow
|
|
||||||
+|FuraMono-Medium Powerline.otf | | Fura Mono Powerline Medium | | Fura Mono Powerline Medium | | Regular |X| Fura Mono Powerline | | Medium
|
|
||||||
-|FuraMono-Medium Powerline.otf | | Fira Mono Medium for Powerline | | Fira Mono Medium for Powerline | | Regular | | Fira Mono Medium for Powerline | | Medium
|
|
||||||
#### No need to have Typographic Family/Subfamily if it is identical to normal Family/Subfamily
|
|
||||||
+|FuraMono-Regular Powerline.otf | | Fura Mono Powerline | | Fura Mono Powerline | | Regular |X| | |
|
|
||||||
-|FuraMono-Regular Powerline.otf | | Fira Mono | | Fira Mono for Powerline | | Regular | | Fira Mono for Powerline | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|gohufont-11.ttf | | Gohufont 11 | | Gohufont 11 |X| Regular | | | |
|
|
||||||
-|gohufont-11.ttf | | GohuFont | | GohuFont | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|gohufont-14.ttf | | Gohufont 14 | | Gohufont 14 |X| Regular | | | |
|
|
||||||
-|gohufont-14.ttf | | GohuFont | | GohuFont | | 14 | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|gohufont-uni-11.ttf | | Gohufont uni-11 | | Gohufont uni-11 |X| Regular | | | |
|
|
||||||
-|gohufont-uni-11.ttf | | GohuFont | | GohuFont | | Medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|gohufont-uni-14.ttf | | Gohufont uni-14 | | Gohufont uni-14 |X| Regular | | | |
|
|
||||||
-|gohufont-uni-14.ttf | | GohuFont | | GohuFont | | uni-14 | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, Normal is usually equivalent to Regular
|
|
||||||
+|heavy_data.ttf | | Heavy Data | | Heavy Data |X| Regular | | | |
|
|
||||||
-|heavy_data.ttf | | Heavy Data | | Heavy Data | | Normal | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|Hermit-light.otf | | Hermit Light |X| Hermit Light |X| Regular |X| Hermit |X| Light
|
|
||||||
-|Hermit-light.otf | | Hermit Light | | Hermit | | light | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Subfamily name into Family instead
|
|
||||||
+|Hermit-medium.otf | | Hermit Medium |X| Hermit Medium |X| Regular |X| Hermit |X| Medium
|
|
||||||
-|Hermit-medium.otf | | Hermit Medium | | Hermit | | medium | | | |
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Bold into Subfamily name
|
|
||||||
+|iAWriterDuospace-Bold.otf | | iA Writer Duospace Bold |X| iA Writer Duospace |X| Bold | | | |
|
|
||||||
-|iAWriterDuospace-Bold.otf | | iA Writer Duospace Bold | | iA Writer Duospace Bold | | Regular | | iA Writer Duospace | | Bold
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Bold into Subfamily name
|
|
||||||
+|iAWriterDuospace-Bold.ttf | | iA Writer Duospace Bold |X| iA Writer Duospace |X| Bold | | | |
|
|
||||||
-|iAWriterDuospace-Bold.ttf | | iA Writer Duospace Bold | | iA Writer Duospace Bold | | Regular | | iA Writer Duospace | | Bold
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Bold into Subfamily name
|
|
||||||
+|iAWriterDuospace-BoldItalic.otf | | iA Writer Duospace Bold Italic |X| iA Writer Duospace |X| Bold Italic | | |X|
|
|
||||||
-|iAWriterDuospace-BoldItalic.otf | | iA Writer Duospace BoldItalic | | iA Writer Duospace Bold | | Italic | | iA Writer Duospace | | BoldItalic
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Bold into Subfamily name
|
|
||||||
+|iAWriterDuospace-BoldItalic.ttf | | iA Writer Duospace Bold Italic |X| iA Writer Duospace |X| Bold Italic | | |X|
|
|
||||||
-|iAWriterDuospace-BoldItalic.ttf | | iA Writer Duospace BoldItalic | | iA Writer Duospace Bold | | Italic | | iA Writer Duospace | | BoldItalic
|
|
||||||
#### Ignore naming part Text
|
|
||||||
+|IBMPlexMono-TextItalic.ttf | | IBM Plex Mono Text Italic | | IBM Plex Mono Text | | Italic |X| |X|
|
|
||||||
-|IBMPlexMono-TextItalic.ttf | | IBM Plex Mono Text Italic | | IBM Plex Mono Text | | Italic | | IBM Plex Mono | | Text Italic
|
|
||||||
#### Ignore naming part Text
|
|
||||||
+|IBMPlexMono-Text.ttf | | IBM Plex Mono Text | | IBM Plex Mono Text | | Regular |X| |X|
|
|
||||||
-|IBMPlexMono-Text.ttf | | IBM Plex Mono Text | | IBM Plex Mono Text | | Regular | | IBM Plex Mono | | Text
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-boldoblique.ttf | | Iosevka Bold Oblique | | Iosevka Oblique |X| Bold Italic | | Iosevka | | Bold Oblique
|
|
||||||
-|iosevka-boldoblique.ttf | | Iosevka Bold Oblique | | Iosevka Oblique | | Bold | | Iosevka | | Bold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-boldoblique.ttf | | Iosevka Term Bold Oblique | | Iosevka Term Oblique |X| Bold Italic | | Iosevka Term | | Bold Oblique
|
|
||||||
-|iosevka-term-boldoblique.ttf | | Iosevka Term Bold Oblique | | Iosevka Term Oblique | | Bold | | Iosevka Term | | Bold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-extraboldoblique.ttf | | Iosevka ExtraBold Oblique | | Iosevka ExtraBold Oblique |X| Italic | | Iosevka | | ExtraBold Oblique
|
|
||||||
-|iosevka-extraboldoblique.ttf | | Iosevka Extrabold Oblique | | Iosevka Extrabold Oblique | | Regular | | Iosevka | | Extrabold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-extraboldoblique.ttf | | Iosevka Term ExtraBold Oblique | | Iosevka Term ExtraBold Oblique |X| Italic | | Iosevka Term | | ExtraBold Oblique
|
|
||||||
-|iosevka-term-extraboldoblique.ttf | | Iosevka Term Extrabold Oblique | | Iosevka Term Extrabold Oblique | | Regular | | Iosevka Term | | Extrabold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-extralightoblique.ttf | | Iosevka ExtraLight Oblique | | Iosevka ExtraLight Oblique |X| Italic | | Iosevka | | ExtraLight Oblique
|
|
||||||
-|iosevka-extralightoblique.ttf | | Iosevka Extralight Oblique | | Iosevka Extralight Oblique | | Regular | | Iosevka | | Extralight Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-extralightoblique.ttf | | Iosevka Term ExtraLight Oblique | | Iosevka Term ExtraLight Obliqu |X| Italic | | Iosevka Term | | ExtraLight Oblique
|
|
||||||
-|iosevka-term-extralightoblique.ttf | | Iosevka Term Extralight Oblique | | Iosevka Term XLtObl | | Regular | | Iosevka Term | | Extralight Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-heavyoblique.ttf | | Iosevka Heavy Oblique | | Iosevka Heavy Oblique |X| Italic | | Iosevka | | Heavy Oblique
|
|
||||||
-|iosevka-heavyoblique.ttf | | Iosevka Heavy Oblique | | Iosevka Heavy Oblique | | Regular | | Iosevka | | Heavy Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-heavyoblique.ttf | | Iosevka Term Heavy Oblique | | Iosevka Term Heavy Oblique |X| Italic | | Iosevka Term | | Heavy Oblique
|
|
||||||
-|iosevka-term-heavyoblique.ttf | | Iosevka Term Heavy Oblique | | Iosevka Term Heavy Oblique | | Regular | | Iosevka Term | | Heavy Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-lightoblique.ttf | | Iosevka Light Oblique | | Iosevka Light Oblique |X| Italic | | Iosevka | | Light Oblique
|
|
||||||
-|iosevka-lightoblique.ttf | | Iosevka Light Oblique | | Iosevka Light Oblique | | Regular | | Iosevka | | Light Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-lightoblique.ttf | | Iosevka Term Light Oblique | | Iosevka Term Light Oblique |X| Italic | | Iosevka Term | | Light Oblique
|
|
||||||
-|iosevka-term-lightoblique.ttf | | Iosevka Term Light Oblique | | Iosevka Term Light Oblique | | Regular | | Iosevka Term | | Light Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-mediumoblique.ttf | | Iosevka Medium Oblique | | Iosevka Medium Oblique |X| Italic | | Iosevka | | Medium Oblique
|
|
||||||
-|iosevka-mediumoblique.ttf | | Iosevka Medium Oblique | | Iosevka Medium Oblique | | Regular | | Iosevka | | Medium Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-mediumoblique.ttf | | Iosevka Term Medium Oblique | | Iosevka Term Medium Oblique |X| Italic | | Iosevka Term | | Medium Oblique
|
|
||||||
-|iosevka-term-mediumoblique.ttf | | Iosevka Term Medium Oblique | | Iosevka Term Medium Oblique | | Regular | | Iosevka Term | | Medium Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-oblique.ttf | | Iosevka Oblique | | Iosevka Oblique |X| Italic | | Iosevka | | Oblique
|
|
||||||
-|iosevka-oblique.ttf | | Iosevka Oblique | | Iosevka Oblique | | Regular | | Iosevka | | Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-oblique.ttf | | Iosevka Term Oblique | | Iosevka Term Oblique |X| Italic | | Iosevka Term | | Oblique
|
|
||||||
-|iosevka-term-oblique.ttf | | Iosevka Term Oblique | | Iosevka Term Oblique | | Regular | | Iosevka Term | | Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-semiboldoblique.ttf | | Iosevka SemiBold Oblique | | Iosevka SemiBold Oblique |X| Italic | | Iosevka | | SemiBold Oblique
|
|
||||||
-|iosevka-semiboldoblique.ttf | | Iosevka Semibold Oblique | | Iosevka Semibold Oblique | | Regular | | Iosevka | | Semibold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-semiboldoblique.ttf | | Iosevka Term SemiBold Oblique | | Iosevka Term SemiBold Oblique |X| Italic | | Iosevka Term | | SemiBold Oblique
|
|
||||||
-|iosevka-term-semiboldoblique.ttf | | Iosevka Term Semibold Oblique | | Iosevka Term Semibold Oblique | | Regular | | Iosevka Term | | Semibold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-term-thinoblique.ttf | | Iosevka Term Thin Oblique | | Iosevka Term Thin Oblique |X| Italic | | Iosevka Term | | Thin Oblique
|
|
||||||
-|iosevka-term-thinoblique.ttf | | Iosevka Term Thin Oblique | | Iosevka Term Thin Oblique | | Regular | | Iosevka Term | | Thin Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead (and mark it Italic so applications know it's slanted) & Keep the grouping in Typographic Family
|
|
||||||
+|iosevka-thinoblique.ttf | | Iosevka Thin Oblique | | Iosevka Thin Oblique |X| Italic | | Iosevka | | Thin Oblique
|
|
||||||
-|iosevka-thinoblique.ttf | | Iosevka Thin Oblique | | Iosevka Thin Oblique | | Regular | | Iosevka | | Thin Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Retina into Family instead
|
|
||||||
+|Monoid-Retina.ttf | | Monoid Retina |X| Monoid Retina |X| Regular |X| Monoid |X| Retina
|
|
||||||
-|Monoid-Retina.ttf | | Monoid Retina | | Monoid | | Retina | | | |
|
|
||||||
#### Remove nonstandard BoldItalic typographic style
|
|
||||||
+|mononoki-BoldItalic.ttf | | Mononoki Bold Italic | | Mononoki | | Bold Italic | | |X|
|
|
||||||
-|mononoki-BoldItalic.ttf | | mononoki Bold Italic | | mononoki | | Bold Italic | | | | BoldItalic
|
|
||||||
#### They say SemiBold is the same as Light Bold, we can not generalize this and make SemiBold self standing
|
|
||||||
+|overpass-mono-semibold.otf | | Overpass Mono SemiBold |X| Overpass Mono SemiBold |X| Regular | | Overpass Mono | | SemiBold
|
|
||||||
-|overpass-mono-semibold.otf | | Overpass Mono SemiBold | | Overpass Mono Light | | Bold | | Overpass Mono | | SemiBold
|
|
||||||
#### They say SemiBold is the same as Light Bold, we can not generalize this and make SemiBold self standing
|
|
||||||
+|overpass-semibold.otf | | Overpass SemiBold |X| Overpass SemiBold |X| Regular | | Overpass | | SemiBold
|
|
||||||
-|overpass-semibold.otf | | Overpass SemiBold | | Overpass Light | | Bold | | Overpass | | SemiBold
|
|
||||||
#### Nonstandard font naming: fullname shall be same as familyname plus more
|
|
||||||
+|ProFontIIx.ttf | | ProFont IIx |X| ProFont IIx | | Regular | | | |
|
|
||||||
-|ProFontIIx.ttf | | ProFont IIx | | ProFontIIx | | Regular | | | |
|
|
||||||
#### We are fine here (just list with exclamation mark because it is a potentially problematic case)
|
|
||||||
!|ProFontWindows.ttf | | ProFontWindows | | ProFontWindows | | Regular | | | |
|
|
||||||
|ProFontWindows.ttf | | ProFontWindows | | ProFontWindows | | Regular | | | |
|
|
||||||
#### No mention of TT in file name
|
|
||||||
+|ProggyCleanCE.ttf |X| ProggyClean CE |X| ProggyClean CE | | Regular | | | |
|
|
||||||
-|ProggyCleanCE.ttf | | ProggyCleanTT CE | | ProggyCleanTT CE | | Regular | | | |
|
|
||||||
#### No mention of TT in file name
|
|
||||||
!|ProggyClean.ttf |X| ProggyClean |X| ProggyClean | | Regular | | | |
|
|
||||||
-|ProggyClean.ttf | | ProggyCleanTT | | ProggyCleanTT | | Regular | | | |
|
|
||||||
#### No mention of TT in file name
|
|
||||||
+|ProggyCleanSZ.ttf |X| ProggyClean SZ |X| ProggyClean SZ | | Regular | | | |
|
|
||||||
-|ProggyCleanSZ.ttf | | ProggyCleanTTSZ | | ProggyCleanTTSZ | | Regular | | | |
|
|
||||||
#### They put one name part in parens
|
|
||||||
+|TerminusTTF-Bold Italic-4.40.1.ttf |X| Terminus TTF Bold Italic |X| Terminus TTF | | Bold Italic | | | |
|
|
||||||
-|TerminusTTF-Bold Italic-4.40.1.ttf | | Terminus (TTF) Bold Italic | | Terminus (TTF) | | Bold Italic | | | |
|
|
||||||
#### They put one name part in parens
|
|
||||||
+|TerminusTTF-Bold-4.40.1.ttf |X| Terminus TTF Bold |X| Terminus TTF | | Bold | | | |
|
|
||||||
-|TerminusTTF-Bold-4.40.1.ttf | | Terminus (TTF) Bold | | Terminus (TTF) | | Bold | | | |
|
|
||||||
#### They put one name part in parens
|
|
||||||
+|TerminusTTF-Italic-4.40.1.ttf |X| Terminus TTF Italic |X| Terminus TTF | | Italic | | | |
|
|
||||||
-|TerminusTTF-Italic-4.40.1.ttf | | Terminus (TTF) Italic | | Terminus (TTF) | | Italic | | | |
|
|
||||||
#### They put one name part in parens
|
|
||||||
+|TerminusTTF-4.40.1.ttf |X| Terminus TTF |X| Terminus TTF |X| Regular | | | |
|
|
||||||
-|TerminusTTF-4.40.1.ttf | | Terminus (TTF) | | Terminus (TTF) | | Medium | | | |
|
|
||||||
#### Ubuntu Condensed should be grouped with Ubuntu, that they didn't is an error?
|
|
||||||
+|Ubuntu-C.ttf | | Ubuntu Condensed | | Ubuntu Condensed | | Regular |X| Ubuntu |X| Condensed
|
|
||||||
-|Ubuntu-C.ttf | | Ubuntu Condensed | | Ubuntu Condensed | | Regular | | Ubuntu Condensed | | Regular
|
|
||||||
#### They say Medium is the same as Light Bold, we can not generalize this and make Medium self standing
|
|
||||||
+|Ubuntu-MI.ttf | | Ubuntu Medium Italic |X| Ubuntu Medium |X| Italic | | Ubuntu | | Medium Italic
|
|
||||||
-|Ubuntu-MI.ttf | | Ubuntu Medium Italic | | Ubuntu Light | | Bold Italic | | Ubuntu | | Medium Italic
|
|
||||||
#### They say Medium is the same as Light Bold, we can not generalize this and make Medium self standing
|
|
||||||
+|Ubuntu-M.ttf | | Ubuntu Medium |X| Ubuntu Medium |X| Regular | | Ubuntu | | Medium
|
|
||||||
-|Ubuntu-M.ttf | | Ubuntu Medium | | Ubuntu Light | | Bold | | Ubuntu | | Medium
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead
|
|
||||||
+|VictorMono-ExtraLightOblique.ttf | | Victor Mono ExtraLight Oblique |X| Victor Mono ExtraLight Oblique | | Italic | | Victor Mono | | ExtraLight Oblique
|
|
||||||
-|VictorMono-ExtraLightOblique.ttf | | Victor Mono ExtraLight Oblique | | Victor Mono ExtraLight | | Italic | | Victor Mono | | ExtraLight Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead
|
|
||||||
+|VictorMono-LightOblique.ttf | | Victor Mono Light Oblique |X| Victor Mono Light Oblique | | Italic | | Victor Mono | | Light Oblique
|
|
||||||
-|VictorMono-LightOblique.ttf | | Victor Mono Light Oblique | | Victor Mono Light | | Italic | | Victor Mono | | Light Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead
|
|
||||||
+|VictorMono-MediumOblique.ttf | | Victor Mono Medium Oblique |X| Victor Mono Medium Oblique | | Italic | | Victor Mono | | Medium Oblique
|
|
||||||
-|VictorMono-MediumOblique.ttf | | Victor Mono Medium Oblique | | Victor Mono Medium | | Italic | | Victor Mono | | Medium Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead
|
|
||||||
+|VictorMono-SemiBoldOblique.ttf | | Victor Mono SemiBold Oblique |X| Victor Mono SemiBold Oblique | | Italic | | Victor Mono | | SemiBold Oblique
|
|
||||||
-|VictorMono-SemiBoldOblique.ttf | | Victor Mono SemiBold Oblique | | Victor Mono SemiBold | | Italic | | Victor Mono | | SemiBold Oblique
|
|
||||||
#### Limit Subfamiliy to 4 standard styles, put Oblique into Family instead
|
|
||||||
+|VictorMono-ThinOblique.ttf | | Victor Mono Thin Oblique |X| Victor Mono Thin Oblique | | Italic | | Victor Mono | | Thin Oblique
|
|
||||||
-|VictorMono-ThinOblique.ttf | | Victor Mono Thin Oblique | | Victor Mono Thin | | Italic | | Victor Mono | | Thin Oblique
|
|
@ -1,195 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# coding=utf8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import os.path
|
|
||||||
import glob
|
|
||||||
import subprocess
|
|
||||||
import fontforge
|
|
||||||
|
|
||||||
###### Some helpers
|
|
||||||
|
|
||||||
def get_sfnt_dict(font):
|
|
||||||
"""Extract SFNT table as nice dict"""
|
|
||||||
d = []
|
|
||||||
for i, el in enumerate(font.sfnt_names):
|
|
||||||
d += [(el[1], el[2])]
|
|
||||||
return dict(d)
|
|
||||||
|
|
||||||
def extract_sfnt_data(sfnt):
|
|
||||||
"""Get the usual names out of the SFNT table"""
|
|
||||||
sfnt_full = sfnt['Fullname']
|
|
||||||
sfnt_fam = sfnt['Family']
|
|
||||||
sfnt_subfam = sfnt['SubFamily']
|
|
||||||
sfnt_pfam = sfnt['Preferred Family'] if 'Preferred Family' in sfnt else ''
|
|
||||||
sfnt_psubfam = sfnt['Preferred Styles'] if 'Preferred Styles' in sfnt else ''
|
|
||||||
return (sfnt_full, sfnt_fam, sfnt_subfam, sfnt_pfam, sfnt_psubfam)
|
|
||||||
|
|
||||||
def format_names(header, *stuff):
|
|
||||||
"""Unify outputs (with header)"""
|
|
||||||
f = '{:1.1}|{:50.50} |{:1.1}| {:65.65} |{:1.1}| {:55.55} |{:1.1}| {:30.30} |{:1.1}| {:40.40} |{:1.1}| {:.40}'
|
|
||||||
if header:
|
|
||||||
d = '------------------------------------------------------------'
|
|
||||||
return f.format(*stuff) + '\n' + f.format('', d, d, d, d, d, d, d, d, d, d, d)
|
|
||||||
return f.format(*stuff).rstrip()
|
|
||||||
|
|
||||||
def lenient_cmp(s1, s2, allow_shuffle_all):
|
|
||||||
"""Compare two font name (parts) but be a bit lenient ;->"""
|
|
||||||
# We do not care about:
|
|
||||||
# - Case
|
|
||||||
# - "Display" vs "Disp" (in Noto)
|
|
||||||
# Allow for "IBM 3278" name
|
|
||||||
s = [ s1, s2 ]
|
|
||||||
for i in range(2):
|
|
||||||
# Usually given transform from 'their' to 'our' style
|
|
||||||
s[i] = s[i].lower()
|
|
||||||
s[i] = re.sub(r'\bdisp\b', 'display', s[i]) # Noto
|
|
||||||
s[i] = s[i].replace('ibm 3270', '3270') # 3270
|
|
||||||
s[i] = s[i].replace('3270-', '3270 ') # 3270
|
|
||||||
s[i] = s[i].replace('lekton-', 'lekton ') # Lekton
|
|
||||||
s[i] = s[i].replace('semi-narrow', 'seminarrow') # 3270
|
|
||||||
s[i] = s[i].replace('bolditalic', 'bold italic')
|
|
||||||
s[i] = re.sub(r'\bfor\b', '', s[i]) # Meslo, Monofur
|
|
||||||
s[i] = re.sub(r'\bpowerline\b', '', s[i]) # Meslo, Monofur
|
|
||||||
s[i] = s[i].replace('fira mono', 'fura mono') # Obviously someone forgot to rename the fonts in Fira/
|
|
||||||
s[i] = s[i].replace('aurulentsansmono-', 'aurulent sans mono ') # Aurulent fullname oddity
|
|
||||||
s[i] = s[i].replace('mononoki-', 'mononoki ') # Mononoki has somtimes a dash
|
|
||||||
s[i] = re.sub(r'\br\b', 'regular', s[i]) # Nonstandard style in Agave
|
|
||||||
s[i] = re.sub(r'(bitstream vera sans mono.*) oblique', r'\1 italic', s[i]) # They call it Oblique but the filename says Italic
|
|
||||||
s[i] = re.sub(r'gohufont (uni-)?(11|14)', 'gohufont', s[i]) # They put the 'name' into the subfamily/weight
|
|
||||||
s[i] = s[i].replace('xltobl', 'extralight oblique') # Iosevka goes inventing names
|
|
||||||
s[i] = re.sub(r'proggyclean(?!TT)( ?)', 'proggycleantt\1', s[i]) # ProggyClean has no TT in filename
|
|
||||||
|
|
||||||
s[i] = re.sub(r' +', ' ', s[i]).strip()
|
|
||||||
|
|
||||||
p = []
|
|
||||||
for e in s:
|
|
||||||
parts = e.split(' ')
|
|
||||||
if not allow_shuffle_all and len(parts) > 2:
|
|
||||||
tail = parts[1:]
|
|
||||||
tail.sort()
|
|
||||||
parts = [parts[0]] + tail
|
|
||||||
elif len(parts) > 1:
|
|
||||||
parts.sort()
|
|
||||||
p.append(' '.join(parts))
|
|
||||||
return p[0] == p[1]
|
|
||||||
|
|
||||||
###### Let's go!
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print('Usage: {} font_name [font_name ...]\n'.format(sys.argv[0]))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
font_patcher = os.path.realpath(os.path.dirname(os.path.realpath(sys.argv[0]))+'/../../../font-patcher')
|
|
||||||
|
|
||||||
existing_font = glob.glob('*.[ot]tf')
|
|
||||||
if len(existing_font):
|
|
||||||
sys.exit('Would overwrite any existing *.ttf and *.otf, bailing out (remove them first)')
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(sys.argv[0] + '.known_issues', 'r') as f:
|
|
||||||
known_issues = f.read().splitlines()
|
|
||||||
# known_issues = [line.rstrip() for line in known_issues]
|
|
||||||
print('Found {:.0f} known issues'.format(len(known_issues) / 4)) # approx ;)
|
|
||||||
except OSError:
|
|
||||||
print('Can not open known_issues file')
|
|
||||||
known_issues = []
|
|
||||||
new_issues = open(sys.argv[0] + '.known_issues.new', 'w')
|
|
||||||
|
|
||||||
print('Examining {} font files'.format(len(sys.argv) - 1))
|
|
||||||
all_files = 0
|
|
||||||
issue_files = 0
|
|
||||||
known_files = 0
|
|
||||||
|
|
||||||
print(format_names(True, '', 'Filename', '', 'Fullname', '', 'Family', '', 'Subfamily', '', 'Typogr. Family', '', 'Typogr. Subfamily'))
|
|
||||||
|
|
||||||
for filename in sys.argv[1:]:
|
|
||||||
data = []
|
|
||||||
fullfile = os.path.basename(filename)
|
|
||||||
fname = os.path.splitext(fullfile)[0]
|
|
||||||
if fname == 'NotoColorEmoji':
|
|
||||||
continue # font is not patchable
|
|
||||||
if fname in [ 'iosevka-heavyoblique', 'iosevka-term-heavyoblique', 'iosevka-mediumoblique', 'Lilex-VF' ]:
|
|
||||||
continue # Patch resultant font not openable
|
|
||||||
log = open("log", "w")
|
|
||||||
log.write(filename)
|
|
||||||
log.close()
|
|
||||||
|
|
||||||
for option in ['--makegroups', '']:
|
|
||||||
cmd = ['fontforge', '--script', font_patcher, '--powerline', option, filename ]
|
|
||||||
cmd = [ c for c in cmd if len(c) ]
|
|
||||||
ff = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, encoding='utf8')
|
|
||||||
#ff = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8')
|
|
||||||
if ff.returncode:
|
|
||||||
print("\nERROR running command:\n {}\n\n{}".format(' '.join(cmd), ''))#ff.stdout))
|
|
||||||
sys.exit(1)
|
|
||||||
new_font = glob.glob('*.[ot]tf')
|
|
||||||
font = fontforge.open(new_font[0], 1)
|
|
||||||
sfnt = get_sfnt_dict(font)
|
|
||||||
font.close()
|
|
||||||
os.system('rm -f *.[ot]tf')
|
|
||||||
(sfnt_full, sfnt_fam, sfnt_subfam, sfnt_pfam, sfnt_psubfam) = extract_sfnt_data(sfnt)
|
|
||||||
|
|
||||||
data.append(( os.path.basename(new_font[0]), sfnt_full, sfnt_fam, sfnt_subfam, sfnt_pfam, sfnt_psubfam ))
|
|
||||||
|
|
||||||
all_files += 1
|
|
||||||
|
|
||||||
t1 = not lenient_cmp(data[0][1], data[1][1], False)
|
|
||||||
t2 = not lenient_cmp(data[0][2], data[1][2], False)
|
|
||||||
t3 = not lenient_cmp(data[0][3], data[1][3], True)
|
|
||||||
t4 = not lenient_cmp(data[0][4], data[1][4], False)
|
|
||||||
t5 = not lenient_cmp(data[0][5], data[1][5], True)
|
|
||||||
|
|
||||||
# Lenience: Allow for dropping unneeded prefered stuff:
|
|
||||||
# New (sub)family is same as old preferred sub(family)
|
|
||||||
if t4 and data[0][4] == '' and data[1][4].lower() == data[0][2].lower():
|
|
||||||
t4 = False
|
|
||||||
if t5 and data[0][5] == '' and data[1][5].lower() == data[0][3].lower():
|
|
||||||
t5 = False
|
|
||||||
|
|
||||||
if t1 or t2 or t3 or t4 or t5:
|
|
||||||
m1 = '+'; m2 = '-'
|
|
||||||
else:
|
|
||||||
m1 = ''; m2 = ''
|
|
||||||
t1_ = 'X' if t1 else ''
|
|
||||||
t2_ = 'X' if t2 else ''
|
|
||||||
t3_ = 'X' if t3 else ''
|
|
||||||
t4_ = 'X' if t4 else ''
|
|
||||||
t5_ = 'X' if t5 else ''
|
|
||||||
|
|
||||||
o1 = format_names(False, m1, data[0][0], t1_, data[0][1], t2_, data[0][2], t3_, data[0][3], t4_, data[0][4], t5_, data[0][5])
|
|
||||||
o2 = format_names(False, m2, data[1][0], '', data[1][1], '', data[1][2], '', data[1][3], '', data[1][4], '', data[1][5])
|
|
||||||
|
|
||||||
if len(m1):
|
|
||||||
issue_files += 1
|
|
||||||
font = fontforge.open(filename, 1)
|
|
||||||
sfnt = get_sfnt_dict(font)
|
|
||||||
font.close()
|
|
||||||
(sfnt_full, sfnt_fam, sfnt_subfam, sfnt_pfam, sfnt_psubfam) = extract_sfnt_data(sfnt)
|
|
||||||
o3 = format_names(False, '>', os.path.basename(filename), '', sfnt_full, '', sfnt_fam, '', sfnt_subfam, '', sfnt_pfam, '', sfnt_psubfam)
|
|
||||||
if not o1 in known_issues or not o2 in known_issues:
|
|
||||||
new_issues.writelines(['#### AUTOGENERATED\n', o3 + '\n', o1 + '\n', o2 + '\n'])
|
|
||||||
else:
|
|
||||||
known_files += 1
|
|
||||||
idx = known_issues.index(o1) - 2 # should be the index of the explanation line
|
|
||||||
if known_issues[idx][0] != '#':
|
|
||||||
sys.exit('Problem with known issues file, line', known_issues.index(o1))
|
|
||||||
new_issues.writelines([known_issues[idx] + '\n', o3 + '\n', o1 + '\n', o2 + '\n'])
|
|
||||||
# remove known_issue triplet
|
|
||||||
known_issues.pop(idx)
|
|
||||||
known_issues.pop(idx)
|
|
||||||
known_issues.pop(idx)
|
|
||||||
known_issues.pop(idx)
|
|
||||||
|
|
||||||
print(o1, o2, sep='\n')
|
|
||||||
|
|
||||||
print('Fonts with different name rendering: {}/{} ({}/{} are in known_issues)'.format(issue_files, all_files, known_files, issue_files))
|
|
||||||
|
|
||||||
if len(known_issues) > 0:
|
|
||||||
print('There are {} lines not needed in known_issues, appending commented out in new known_issues'.format(len(known_issues)))
|
|
||||||
new_issues.write('\n#### The following lines are not needed anymore\n\n')
|
|
||||||
for l in known_issues:
|
|
||||||
new_issues.writelines([' ', l, '\n'])
|
|
||||||
|
|
||||||
new_issues.close()
|
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# coding=utf8
|
# coding=utf8
|
||||||
|
#
|
||||||
|
# Usually called via
|
||||||
|
# $ fontforge query_names fontfile.tff 2>/dev/null
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
@ -13,10 +16,10 @@ def get_sfnt_dict(font):
|
|||||||
|
|
||||||
def format_names(header, *stuff):
|
def format_names(header, *stuff):
|
||||||
"""Unify outputs (with header)"""
|
"""Unify outputs (with header)"""
|
||||||
f = '{:1.1}|{:50.50} |{:1.1}| {:65.65} |{:1.1}| {:55.55} |{:1.1}| {:30.30} |{:1.1}| {:40.40} |{:1.1}| {:.40}'
|
f = '| {:50.50}|{:>2.2}| {:64.64}|{:>2.2}| {:64.64}|{:>2.2}| {:55.55}|{:>2.2}| {:30.30}|{:>2.2}| {:40.40}|{:>2.2}| {:40.40}|{:>2.2}|'
|
||||||
if header:
|
if header:
|
||||||
d = '------------------------------------------------------------'
|
d = ''
|
||||||
return f.format(*stuff) + '\n' + f.format('', d, d, d, d, d, d, d, d, d, d, d)
|
return f.format(*stuff) + '\n' + f.format(d, d, d, d, d, d, d, d, d, d, d, d, d, d).replace(' ', '-')
|
||||||
return f.format(*stuff).rstrip()
|
return f.format(*stuff).rstrip()
|
||||||
|
|
||||||
###### Let's go!
|
###### Let's go!
|
||||||
@ -27,7 +30,7 @@ if len(sys.argv) < 2:
|
|||||||
|
|
||||||
print('Examining {} font files'.format(len(sys.argv) - 1))
|
print('Examining {} font files'.format(len(sys.argv) - 1))
|
||||||
|
|
||||||
print(format_names(True, '', 'Filename', '', 'Fullname', '', 'Family', '', 'Subfamily', '', 'Typogr. Family', '', 'Typogr. Subfamily'))
|
print(format_names(True, 'Filename', '', 'PS Name', '', 'Fullname', '', 'Family', '', 'Subfamily', '', 'Typogr. Family', '', 'Typogr. Subfamily', ''))
|
||||||
|
|
||||||
for filename in sys.argv[1:]:
|
for filename in sys.argv[1:]:
|
||||||
fullfile = os.path.basename(filename)
|
fullfile = os.path.basename(filename)
|
||||||
@ -35,6 +38,7 @@ for filename in sys.argv[1:]:
|
|||||||
|
|
||||||
font = fontforge.open(filename, 1)
|
font = fontforge.open(filename, 1)
|
||||||
sfnt = get_sfnt_dict(font)
|
sfnt = get_sfnt_dict(font)
|
||||||
|
psname = font.fontname
|
||||||
font.close()
|
font.close()
|
||||||
|
|
||||||
sfnt_full = sfnt['Fullname']
|
sfnt_full = sfnt['Fullname']
|
||||||
@ -43,6 +47,14 @@ for filename in sys.argv[1:]:
|
|||||||
sfnt_pfam = sfnt['Preferred Family'] if 'Preferred Family' in sfnt else ''
|
sfnt_pfam = sfnt['Preferred Family'] if 'Preferred Family' in sfnt else ''
|
||||||
sfnt_psubfam = sfnt['Preferred Styles'] if 'Preferred Styles' in sfnt else ''
|
sfnt_psubfam = sfnt['Preferred Styles'] if 'Preferred Styles' in sfnt else ''
|
||||||
|
|
||||||
o2 = format_names(False, '', fullfile, '', sfnt_full, '', sfnt_fam, '', sfnt_subfam, '', sfnt_pfam, '', sfnt_psubfam)
|
o2 = format_names(False,
|
||||||
|
fullfile, str(len(fullfile)),
|
||||||
|
psname, str(len(psname)),
|
||||||
|
sfnt_full, str(len(sfnt_full)),
|
||||||
|
sfnt_fam, str(len(sfnt_fam)),
|
||||||
|
sfnt_subfam, str(len(sfnt_subfam)),
|
||||||
|
# show length zero if a zero length string is stored, show nothing if nothing is stored:
|
||||||
|
sfnt_pfam, str(len(sfnt_pfam)) if 'Preferred Family' in sfnt else '',
|
||||||
|
sfnt_psubfam, str(len(sfnt_psubfam)) if 'Preferred Family' in sfnt else '')
|
||||||
|
|
||||||
print(o2)
|
print(o2)
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
Add weight/style to family [1]
|
|
||||||
Use only Regular/Bold/Italic in SubFamily [2]
|
|
||||||
Classify Medium as own weight and not Bold [3]
|
|
||||||
Change regular-equivalent name to Regular [4]
|
|
||||||
Drop unneeded Typogr.Family/Typogr.Style [5]
|
|
||||||
Do not call Semibold Light-Bold [6]
|
|
||||||
Fullname has been missing 'Nerd Font' [7]
|
|
||||||
The fonts name is M+ not Mplus [8]
|
|
||||||
Handle Retina as Weight and not Style [9]
|
|
||||||
Bold and Italic are styles of a basefont [10]
|
|
||||||
Put Oblique into own SubFamily (and mark it as italic) [11]
|
|
||||||
'Term' is missing from Family [12]
|
|
||||||
Bold / Bold-Italic are just a styles of Regular [13]
|
|
||||||
Drop Regular from Style [14]
|
|
292
font-patcher
292
font-patcher
@ -6,7 +6,7 @@
|
|||||||
from __future__ import absolute_import, print_function, unicode_literals
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
|
||||||
# Change the script version when you edit this script:
|
# Change the script version when you edit this script:
|
||||||
script_version = "3.7.1"
|
script_version = "4.0.0"
|
||||||
|
|
||||||
version = "2.3.3"
|
version = "2.3.3"
|
||||||
projectName = "Nerd Fonts"
|
projectName = "Nerd Fonts"
|
||||||
@ -22,6 +22,7 @@ import errno
|
|||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
import logging
|
||||||
try:
|
try:
|
||||||
import configparser
|
import configparser
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -239,10 +240,10 @@ def force_panose_monospaced(font):
|
|||||||
panose = list(font.os2_panose)
|
panose = list(font.os2_panose)
|
||||||
if panose[0] == 0: # 0 (1st value) = family kind; 0 = any (default)
|
if panose[0] == 0: # 0 (1st value) = family kind; 0 = any (default)
|
||||||
panose[0] = 2 # make kind latin text and display
|
panose[0] = 2 # make kind latin text and display
|
||||||
print(" Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')")
|
logger.info("Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')")
|
||||||
font.os2_panose = tuple(panose)
|
font.os2_panose = tuple(panose)
|
||||||
if panose[0] == 2 and panose[3] != 9:
|
if panose[0] == 2 and panose[3] != 9:
|
||||||
print(" Setting Panose 'Proportion' to 'Monospaced' (was '{}')".format(panose_proportion_to_text(panose[3])))
|
logger.info("Setting Panose 'Proportion' to 'Monospaced' (was '%s')", panose_proportion_to_text(panose[3]))
|
||||||
panose[3] = 9 # 3 (4th value) = proportion; 9 = monospaced
|
panose[3] = 9 # 3 (4th value) = proportion; 9 = monospaced
|
||||||
font.os2_panose = tuple(panose)
|
font.os2_panose = tuple(panose)
|
||||||
|
|
||||||
@ -296,10 +297,22 @@ def get_old_average_x_width(font):
|
|||||||
}
|
}
|
||||||
for g in weights:
|
for g in weights:
|
||||||
if g not in font:
|
if g not in font:
|
||||||
sys.exit("{}: Can not determine ancient style xAvgCharWidth".format(projectName))
|
logger.critical("Can not determine ancient style xAvgCharWidth")
|
||||||
|
sys.exit(1)
|
||||||
s += font[g].width * weights[g]
|
s += font[g].width * weights[g]
|
||||||
return int(s / 1000)
|
return int(s / 1000)
|
||||||
|
|
||||||
|
def create_filename(fonts):
|
||||||
|
""" Determine filename from font object(s) """
|
||||||
|
sfnt = { k: v for l, k, v in fonts[0].sfnt_names }
|
||||||
|
sfnt_pfam = sfnt.get('Preferred Family', sfnt['Family'])
|
||||||
|
sfnt_psubfam = sfnt.get('Preferred Styles', sfnt['SubFamily'])
|
||||||
|
if len(fonts) > 1:
|
||||||
|
return sfnt_pfam
|
||||||
|
if len(sfnt_psubfam) > 0:
|
||||||
|
sfnt_psubfam = '-' + sfnt_psubfam
|
||||||
|
return (sfnt_pfam + sfnt_psubfam).replace(' ', '')
|
||||||
|
|
||||||
|
|
||||||
class font_patcher:
|
class font_patcher:
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
@ -311,6 +324,7 @@ class font_patcher:
|
|||||||
self.font_dim = None # class 'dict'
|
self.font_dim = None # class 'dict'
|
||||||
self.font_extrawide = False
|
self.font_extrawide = False
|
||||||
self.source_monospaced = None # Later True or False
|
self.source_monospaced = None # Later True or False
|
||||||
|
self.symbolsonly = False
|
||||||
self.onlybitmaps = 0
|
self.onlybitmaps = 0
|
||||||
self.essential = set()
|
self.essential = set()
|
||||||
self.config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True)
|
self.config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True)
|
||||||
@ -336,7 +350,7 @@ class font_patcher:
|
|||||||
|
|
||||||
# For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs
|
# For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs
|
||||||
if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2:
|
if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2:
|
||||||
print("Very wide and short font, disabling 2 cell Powerline glyphs")
|
logger.warning("Very wide and short font, disabling 2 cell Powerline glyphs")
|
||||||
self.font_extrawide = True
|
self.font_extrawide = True
|
||||||
|
|
||||||
# Prevent opening and closing the fontforge font. Makes things faster when patching
|
# Prevent opening and closing the fontforge font. Makes things faster when patching
|
||||||
@ -345,8 +359,12 @@ class font_patcher:
|
|||||||
symfont = None
|
symfont = None
|
||||||
|
|
||||||
if not os.path.isdir(self.args.glyphdir):
|
if not os.path.isdir(self.args.glyphdir):
|
||||||
sys.exit("{}: Can not find symbol glyph directory {} "
|
logger.critical("Can not find symbol glyph directory %s "
|
||||||
"(probably you need to download the src/glyphs/ directory?)".format(projectName, self.args.glyphdir))
|
"(probably you need to download the src/glyphs/ directory?)", self.args.glyphdir)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if self.args.dry_run:
|
||||||
|
return
|
||||||
|
|
||||||
for patch in self.patch_set:
|
for patch in self.patch_set:
|
||||||
if patch['Enabled']:
|
if patch['Enabled']:
|
||||||
@ -356,11 +374,13 @@ class font_patcher:
|
|||||||
symfont.close()
|
symfont.close()
|
||||||
symfont = None
|
symfont = None
|
||||||
if not os.path.isfile(self.args.glyphdir + patch['Filename']):
|
if not os.path.isfile(self.args.glyphdir + patch['Filename']):
|
||||||
sys.exit("{}: Can not find symbol source for '{}'\n{:>{}} (i.e. {})".format(
|
logger.critical("Can not find symbol source for '%s' (i.e. %s)",
|
||||||
projectName, patch['Name'], '', len(projectName), self.args.glyphdir + patch['Filename']))
|
patch['Name'], self.args.glyphdir + patch['Filename'])
|
||||||
|
sys.exit(1)
|
||||||
if not os.access(self.args.glyphdir + patch['Filename'], os.R_OK):
|
if not os.access(self.args.glyphdir + patch['Filename'], os.R_OK):
|
||||||
sys.exit("{}: Can not open symbol source for '{}'\n{:>{}} (i.e. {})".format(
|
logger.critical("Can not open symbol source for '%s' (i.e. %s)",
|
||||||
projectName, patch['Name'], '', len(projectName), self.args.glyphdir + patch['Filename']))
|
patch['Name'], self.args.glyphdir + patch['Filename'])
|
||||||
|
sys.exit(1)
|
||||||
symfont = fontforge.open(os.path.join(self.args.glyphdir, patch['Filename']))
|
symfont = fontforge.open(os.path.join(self.args.glyphdir, patch['Filename']))
|
||||||
symfont.encoding = 'UnicodeFull'
|
symfont.encoding = 'UnicodeFull'
|
||||||
|
|
||||||
@ -402,11 +422,11 @@ class font_patcher:
|
|||||||
break
|
break
|
||||||
outfile = os.path.normpath(os.path.join(
|
outfile = os.path.normpath(os.path.join(
|
||||||
sanitize_filename(self.args.outputdir, True),
|
sanitize_filename(self.args.outputdir, True),
|
||||||
sanitize_filename(sourceFont.familyname) + ".ttc"))
|
sanitize_filename(create_filename(sourceFonts)) + ".ttc"))
|
||||||
sourceFonts[0].generateTtc(outfile, sourceFonts[1:], flags=gen_flags, layer=layer)
|
sourceFonts[0].generateTtc(outfile, sourceFonts[1:], flags=gen_flags, layer=layer)
|
||||||
message = " Generated {} fonts\n \===> '{}'".format(len(sourceFonts), outfile)
|
message = " Generated {} fonts\n \===> '{}'".format(len(sourceFonts), outfile)
|
||||||
else:
|
else:
|
||||||
fontname = sourceFont.fullname
|
fontname = create_filename(sourceFonts)
|
||||||
if not fontname:
|
if not fontname:
|
||||||
fontname = sourceFont.cidfontname
|
fontname = sourceFont.cidfontname
|
||||||
outfile = os.path.normpath(os.path.join(
|
outfile = os.path.normpath(os.path.join(
|
||||||
@ -414,9 +434,11 @@ class font_patcher:
|
|||||||
sanitize_filename(fontname) + self.args.extension))
|
sanitize_filename(fontname) + self.args.extension))
|
||||||
bitmaps = str()
|
bitmaps = str()
|
||||||
if len(self.sourceFont.bitmapSizes):
|
if len(self.sourceFont.bitmapSizes):
|
||||||
if not self.args.quiet:
|
logger.debug("Preserving bitmaps {}".format(self.sourceFont.bitmapSizes))
|
||||||
print("Preserving bitmaps {}".format(self.sourceFont.bitmapSizes))
|
|
||||||
bitmaps = str('otf') # otf/ttf, both is bf_ttf
|
bitmaps = str('otf') # otf/ttf, both is bf_ttf
|
||||||
|
if self.args.dry_run:
|
||||||
|
logger.debug("=====> Filename '{}'".format(outfile))
|
||||||
|
return
|
||||||
sourceFont.generate(outfile, bitmap_type=bitmaps, flags=gen_flags)
|
sourceFont.generate(outfile, bitmap_type=bitmaps, flags=gen_flags)
|
||||||
message = " {}\n \===> '{}'".format(self.sourceFont.fullname, outfile)
|
message = " {}\n \===> '{}'".format(self.sourceFont.fullname, outfile)
|
||||||
|
|
||||||
@ -426,8 +448,7 @@ class font_patcher:
|
|||||||
source_font = TableHEADWriter(self.args.font)
|
source_font = TableHEADWriter(self.args.font)
|
||||||
dest_font = TableHEADWriter(outfile)
|
dest_font = TableHEADWriter(outfile)
|
||||||
for idx in range(source_font.num_fonts):
|
for idx in range(source_font.num_fonts):
|
||||||
if not self.args.quiet:
|
logger.debug("Tweaking %d/%d", idx + 1, source_font.num_fonts)
|
||||||
print("{}: Tweaking {}/{}".format(projectName, idx + 1, source_font.num_fonts))
|
|
||||||
xwidth_s = ''
|
xwidth_s = ''
|
||||||
xwidth = self.xavgwidth[idx]
|
xwidth = self.xavgwidth[idx]
|
||||||
if isinstance(xwidth, int):
|
if isinstance(xwidth, int):
|
||||||
@ -438,26 +459,23 @@ class font_patcher:
|
|||||||
dest_font.find_table([b'OS/2'], idx)
|
dest_font.find_table([b'OS/2'], idx)
|
||||||
d_xwidth = dest_font.getshort('avgWidth')
|
d_xwidth = dest_font.getshort('avgWidth')
|
||||||
if d_xwidth != xwidth:
|
if d_xwidth != xwidth:
|
||||||
if not self.args.quiet:
|
logger.debug("Changing xAvgCharWidth from %d to %d%s", d_xwidth, xwidth, xwidth_s)
|
||||||
print("Changing xAvgCharWidth from {} to {}{}".format(d_xwidth, xwidth, xwidth_s))
|
|
||||||
dest_font.putshort(xwidth, 'avgWidth')
|
dest_font.putshort(xwidth, 'avgWidth')
|
||||||
dest_font.reset_table_checksum()
|
dest_font.reset_table_checksum()
|
||||||
source_font.find_head_table(idx)
|
source_font.find_head_table(idx)
|
||||||
dest_font.find_head_table(idx)
|
dest_font.find_head_table(idx)
|
||||||
if source_font.flags & 0x08 == 0 and dest_font.flags & 0x08 != 0:
|
if source_font.flags & 0x08 == 0 and dest_font.flags & 0x08 != 0:
|
||||||
if not self.args.quiet:
|
logger.debug("Changing flags from 0x%X to 0x%X", dest_font.flags, dest_font.flags & ~0x08)
|
||||||
print("Changing flags from 0x{:X} to 0x{:X}".format(dest_font.flags, dest_font.flags & ~0x08))
|
|
||||||
dest_font.putshort(dest_font.flags & ~0x08, 'flags') # clear 'ppem_to_int'
|
dest_font.putshort(dest_font.flags & ~0x08, 'flags') # clear 'ppem_to_int'
|
||||||
if source_font.lowppem != dest_font.lowppem:
|
if source_font.lowppem != dest_font.lowppem:
|
||||||
if not self.args.quiet:
|
logger.debug("Changing lowestRecPPEM from %d to %d", dest_font.lowppem, source_font.lowppem)
|
||||||
print("Changing lowestRecPPEM from {} to {}".format(dest_font.lowppem, source_font.lowppem))
|
|
||||||
dest_font.putshort(source_font.lowppem, 'lowestRecPPEM')
|
dest_font.putshort(source_font.lowppem, 'lowestRecPPEM')
|
||||||
if dest_font.modified:
|
if dest_font.modified:
|
||||||
dest_font.reset_table_checksum()
|
dest_font.reset_table_checksum()
|
||||||
if dest_font.modified:
|
if dest_font.modified:
|
||||||
dest_font.reset_full_checksum()
|
dest_font.reset_full_checksum()
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print("Can not handle font flags ({})".format(repr(error)))
|
logger.error("Can not handle font flags (%s)", repr(error))
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
source_font.close()
|
source_font.close()
|
||||||
@ -465,12 +483,13 @@ class font_patcher:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if self.args.is_variable:
|
if self.args.is_variable:
|
||||||
print("Warning: Source font is a variable open type font (VF) and the patch results will most likely not be what you want")
|
logger.error("Source font is a variable open type font (VF) and the patch results will most likely not be what you want")
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
if self.args.postprocess:
|
if self.args.postprocess:
|
||||||
subprocess.call([self.args.postprocess, outfile])
|
subprocess.call([self.args.postprocess, outfile])
|
||||||
print("\nPost Processed: {}".format(outfile))
|
print("\n")
|
||||||
|
logger.info("Post Processed: %s", outfile)
|
||||||
|
|
||||||
|
|
||||||
def setup_name_backup(self, font):
|
def setup_name_backup(self, font):
|
||||||
@ -488,11 +507,8 @@ class font_patcher:
|
|||||||
font.fullname = font.persistent["fullname"]
|
font.fullname = font.persistent["fullname"]
|
||||||
if isinstance(font.persistent["familyname"], str):
|
if isinstance(font.persistent["familyname"], str):
|
||||||
font.familyname = font.persistent["familyname"]
|
font.familyname = font.persistent["familyname"]
|
||||||
verboseAdditionalFontNameSuffix = " " + projectNameSingular
|
verboseAdditionalFontNameSuffix = ""
|
||||||
if self.args.windows: # attempt to shorten here on the additional name BEFORE trimming later
|
additionalFontNameSuffix = ""
|
||||||
additionalFontNameSuffix = " " + projectNameAbbreviation
|
|
||||||
else:
|
|
||||||
additionalFontNameSuffix = verboseAdditionalFontNameSuffix
|
|
||||||
if not self.args.complete:
|
if not self.args.complete:
|
||||||
# NOTE not all symbol fonts have appended their suffix here
|
# NOTE not all symbol fonts have appended their suffix here
|
||||||
if self.args.fontawesome:
|
if self.args.fontawesome:
|
||||||
@ -523,17 +539,24 @@ class font_patcher:
|
|||||||
additionalFontNameSuffix += " WEA"
|
additionalFontNameSuffix += " WEA"
|
||||||
verboseAdditionalFontNameSuffix += " Plus Weather Icons"
|
verboseAdditionalFontNameSuffix += " Plus Weather Icons"
|
||||||
|
|
||||||
# if all source glyphs included simplify the name
|
# add mono signifier to beginning of name suffix
|
||||||
else:
|
|
||||||
additionalFontNameSuffix = " " + projectNameSingular + " Complete"
|
|
||||||
verboseAdditionalFontNameSuffix = " " + projectNameSingular + " Complete"
|
|
||||||
|
|
||||||
# add mono signifier to end of name
|
|
||||||
if self.args.single:
|
if self.args.single:
|
||||||
additionalFontNameSuffix += " M"
|
variant_abbrev = "M"
|
||||||
verboseAdditionalFontNameSuffix += " Mono"
|
variant_full = " Mono"
|
||||||
|
elif self.args.nonmono and not self.symbolsonly:
|
||||||
|
variant_abbrev = "P"
|
||||||
|
variant_full = " Propo"
|
||||||
|
else:
|
||||||
|
variant_abbrev = ""
|
||||||
|
variant_full = ""
|
||||||
|
|
||||||
if FontnameParserOK and self.args.makegroups:
|
ps_suffix = projectNameAbbreviation + variant_abbrev + additionalFontNameSuffix
|
||||||
|
|
||||||
|
# add 'Nerd Font' to beginning of name suffix
|
||||||
|
verboseAdditionalFontNameSuffix = " " + projectNameSingular + variant_full + verboseAdditionalFontNameSuffix
|
||||||
|
additionalFontNameSuffix = " " + projectNameSingular + variant_full + additionalFontNameSuffix
|
||||||
|
|
||||||
|
if FontnameParserOK and self.args.makegroups > 0:
|
||||||
use_fullname = isinstance(font.fullname, str) # Usually the fullname is better to parse
|
use_fullname = isinstance(font.fullname, str) # Usually the fullname is better to parse
|
||||||
# Use fullname if it is 'equal' to the fontname
|
# Use fullname if it is 'equal' to the fontname
|
||||||
if font.fullname:
|
if font.fullname:
|
||||||
@ -545,12 +568,11 @@ class font_patcher:
|
|||||||
# Gohu fontnames hide the weight, but the file names are ok...
|
# Gohu fontnames hide the weight, but the file names are ok...
|
||||||
if parser_name.startswith('Gohu'):
|
if parser_name.startswith('Gohu'):
|
||||||
parser_name = os.path.splitext(os.path.basename(self.args.font))[0]
|
parser_name = os.path.splitext(os.path.basename(self.args.font))[0]
|
||||||
n = FontnameParser(parser_name)
|
n = FontnameParser(parser_name, logger)
|
||||||
if not n.parse_ok:
|
if not n.parse_ok:
|
||||||
print("Have only minimal naming information, check resulting name. Maybe omit --makegroups option")
|
logger.warning("Have only minimal naming information, check resulting name. Maybe specify --makegroups 0")
|
||||||
n.drop_for_powerline()
|
n.drop_for_powerline()
|
||||||
n.enable_short_families(True, "Noto")
|
n.enable_short_families(True, self.args.makegroups in [ 2, 3, 5, 6, ], self.args.makegroups in [ 3, 6, ])
|
||||||
n.set_for_windows(self.args.windows)
|
|
||||||
|
|
||||||
# All the following stuff is ignored in makegroups-mode
|
# All the following stuff is ignored in makegroups-mode
|
||||||
|
|
||||||
@ -598,23 +620,7 @@ class font_patcher:
|
|||||||
if len(subFamily) == 0:
|
if len(subFamily) == 0:
|
||||||
subFamily = "Regular"
|
subFamily = "Regular"
|
||||||
|
|
||||||
if self.args.windows:
|
familyname += " " + projectNameSingular + variant_full
|
||||||
maxFamilyLength = 31
|
|
||||||
maxFontLength = maxFamilyLength - len('-' + subFamily)
|
|
||||||
familyname += " " + projectNameAbbreviation
|
|
||||||
if self.args.single:
|
|
||||||
familyname += "M"
|
|
||||||
fullname += " Windows Compatible"
|
|
||||||
|
|
||||||
# now make sure less than 32 characters name length
|
|
||||||
if len(fontname) > maxFontLength:
|
|
||||||
fontname = fontname[:maxFontLength]
|
|
||||||
if len(familyname) > maxFamilyLength:
|
|
||||||
familyname = familyname[:maxFamilyLength]
|
|
||||||
else:
|
|
||||||
familyname += " " + projectNameSingular
|
|
||||||
if self.args.single:
|
|
||||||
familyname += " Mono"
|
|
||||||
|
|
||||||
# Don't truncate the subfamily to keep fontname unique. MacOS treats fonts with
|
# Don't truncate the subfamily to keep fontname unique. MacOS treats fonts with
|
||||||
# the same name as the same font, even if subFamily is different. Make sure to
|
# the same name as the same font, even if subFamily is different. Make sure to
|
||||||
@ -693,7 +699,7 @@ class font_patcher:
|
|||||||
fullname = replace_font_name(fullname, additionalFontNameReplacements2)
|
fullname = replace_font_name(fullname, additionalFontNameReplacements2)
|
||||||
fontname = replace_font_name(fontname, additionalFontNameReplacements2)
|
fontname = replace_font_name(fontname, additionalFontNameReplacements2)
|
||||||
|
|
||||||
if not (FontnameParserOK and self.args.makegroups):
|
if not (FontnameParserOK and self.args.makegroups > 0):
|
||||||
# replace any extra whitespace characters:
|
# replace any extra whitespace characters:
|
||||||
font.familyname = " ".join(familyname.split())
|
font.familyname = " ".join(familyname.split())
|
||||||
font.fullname = " ".join(fullname.split())
|
font.fullname = " ".join(fullname.split())
|
||||||
@ -704,13 +710,9 @@ class font_patcher:
|
|||||||
font.appendSFNTName(str('English (US)'), str('Compatible Full'), font.fullname)
|
font.appendSFNTName(str('English (US)'), str('Compatible Full'), font.fullname)
|
||||||
font.appendSFNTName(str('English (US)'), str('SubFamily'), subFamily)
|
font.appendSFNTName(str('English (US)'), str('SubFamily'), subFamily)
|
||||||
else:
|
else:
|
||||||
fam_suffix = projectNameSingular if not self.args.windows else projectNameAbbreviation
|
short_family = projectNameAbbreviation + variant_abbrev if self.args.makegroups >= 4 else projectNameSingular + variant_full
|
||||||
if self.args.single:
|
# inject_suffix(family, ps_fontname, short_family)
|
||||||
if self.args.windows:
|
n.inject_suffix(verboseAdditionalFontNameSuffix, ps_suffix, short_family)
|
||||||
fam_suffix += 'M'
|
|
||||||
else:
|
|
||||||
fam_suffix += ' Mono'
|
|
||||||
n.inject_suffix(verboseAdditionalFontNameSuffix, additionalFontNameSuffix, fam_suffix)
|
|
||||||
n.rename_font(font)
|
n.rename_font(font)
|
||||||
|
|
||||||
font.comment = projectInfo
|
font.comment = projectInfo
|
||||||
@ -726,6 +728,7 @@ class font_patcher:
|
|||||||
self.sourceFont.version = str(self.sourceFont.cidversion) + ";" + projectName + " " + version
|
self.sourceFont.version = str(self.sourceFont.cidversion) + ";" + projectName + " " + version
|
||||||
self.sourceFont.sfntRevision = None # Auto-set (refreshed) by fontforge
|
self.sourceFont.sfntRevision = None # Auto-set (refreshed) by fontforge
|
||||||
self.sourceFont.appendSFNTName(str('English (US)'), str('Version'), "Version " + self.sourceFont.version)
|
self.sourceFont.appendSFNTName(str('English (US)'), str('Version'), "Version " + self.sourceFont.version)
|
||||||
|
# The Version SFNT name is later reused by the NameParser for UniqueID
|
||||||
# print("Version now is {}".format(sourceFont.version))
|
# print("Version now is {}".format(sourceFont.version))
|
||||||
|
|
||||||
|
|
||||||
@ -734,17 +737,17 @@ class font_patcher:
|
|||||||
# the tables have been removed from the repo with >this< commit
|
# the tables have been removed from the repo with >this< commit
|
||||||
if self.args.configfile and self.config.read(self.args.configfile):
|
if self.args.configfile and self.config.read(self.args.configfile):
|
||||||
if self.args.removeligatures:
|
if self.args.removeligatures:
|
||||||
print("Removing ligatures from configfile `Subtables` section")
|
logger.info("Removing ligatures from configfile `Subtables` section")
|
||||||
ligature_subtables = json.loads(self.config.get("Subtables", "ligatures"))
|
ligature_subtables = json.loads(self.config.get("Subtables", "ligatures"))
|
||||||
for subtable in ligature_subtables:
|
for subtable in ligature_subtables:
|
||||||
print("Removing subtable:", subtable)
|
logger.debug("Removing subtable: %s", subtable)
|
||||||
try:
|
try:
|
||||||
self.sourceFont.removeLookupSubtable(subtable)
|
self.sourceFont.removeLookupSubtable(subtable)
|
||||||
print("Successfully removed subtable:", subtable)
|
logger.debug("Successfully removed subtable: %s", subtable)
|
||||||
except Exception:
|
except Exception:
|
||||||
print("Failed to remove subtable:", subtable)
|
logger.error("Failed to remove subtable: %s", subtable)
|
||||||
elif self.args.removeligatures:
|
elif self.args.removeligatures:
|
||||||
print("Unable to read configfile, unable to remove ligatures")
|
logger.error("Unable to read configfile, unable to remove ligatures")
|
||||||
|
|
||||||
|
|
||||||
def assert_monospace(self):
|
def assert_monospace(self):
|
||||||
@ -756,16 +759,17 @@ class font_patcher:
|
|||||||
panose_mono = check_panose_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'
|
# 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):
|
if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1):
|
||||||
print(" Warning: Monospaced check: Panose assumed to be wrong")
|
logger.warning("Monospaced check: Panose assumed to be wrong")
|
||||||
print(" {} and {}".format(
|
logger.warning(" %s and %s",
|
||||||
report_advance_widths(self.sourceFont),
|
report_advance_widths(self.sourceFont),
|
||||||
panose_check_to_text(panose_mono, self.sourceFont.os2_panose)))
|
panose_check_to_text(panose_mono, self.sourceFont.os2_panose))
|
||||||
if self.args.single and not width_mono:
|
if self.args.single and not width_mono:
|
||||||
print(" Warning: Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless")
|
logger.warning("Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless")
|
||||||
if offending_char is not None:
|
if offending_char is not None:
|
||||||
print(" Offending char: 0x{:X}".format(offending_char))
|
logger.warning(" Offending char: %X", offending_char)
|
||||||
if self.args.single <= 1:
|
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")
|
logger.critical("Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching")
|
||||||
|
sys.exit(1)
|
||||||
if width_mono:
|
if width_mono:
|
||||||
force_panose_monospaced(self.sourceFont)
|
force_panose_monospaced(self.sourceFont)
|
||||||
|
|
||||||
@ -781,9 +785,9 @@ class font_patcher:
|
|||||||
box_glyphs_current = len(list(self.sourceFont.selection.byGlyphs))
|
box_glyphs_current = len(list(self.sourceFont.selection.byGlyphs))
|
||||||
if box_glyphs_target > box_glyphs_current:
|
if box_glyphs_target > box_glyphs_current:
|
||||||
# Sourcefont does not have all of these glyphs, do not mix sets (overwrite existing)
|
# Sourcefont does not have all of these glyphs, do not mix sets (overwrite existing)
|
||||||
if not self.args.quiet and box_glyphs_current > 0:
|
if box_glyphs_current > 0:
|
||||||
print("INFO: {}/{} box drawing glyphs will be replaced".format(
|
logger.debug("%d/%d box drawing glyphs will be replaced",
|
||||||
box_glyphs_current, box_glyphs_target))
|
box_glyphs_current, box_glyphs_target)
|
||||||
box_enabled = True
|
box_enabled = True
|
||||||
else:
|
else:
|
||||||
# Sourcefont does have all of these glyphs
|
# Sourcefont does have all of these glyphs
|
||||||
@ -1104,7 +1108,7 @@ class font_patcher:
|
|||||||
metrics = Metric.TYPO if use_typo else Metric.WIN # conforming font
|
metrics = Metric.TYPO if use_typo else Metric.WIN # conforming font
|
||||||
else:
|
else:
|
||||||
# We trust the WIN metric more, see experiments in #1056
|
# We trust the WIN metric more, see experiments in #1056
|
||||||
print("{}: WARNING Font vertical metrics inconsistent (HHEA {} / TYPO {} / WIN {}), using WIN".format(projectName, hhea_btb, typo_btb, win_btb))
|
logger.warning("Font vertical metrics inconsistent (HHEA %d / TYPO %d / WIN %d), using WIN", hhea_btb, typo_btb, win_btb)
|
||||||
our_btb = win_btb
|
our_btb = win_btb
|
||||||
metrics = Metric.WIN
|
metrics = Metric.WIN
|
||||||
|
|
||||||
@ -1129,6 +1133,7 @@ class font_patcher:
|
|||||||
if self.font_dim['height'] == 0:
|
if self.font_dim['height'] == 0:
|
||||||
# This can only happen if the input font is empty
|
# This can only happen if the input font is empty
|
||||||
# Assume we are using our prepared templates
|
# Assume we are using our prepared templates
|
||||||
|
self.symbolsonly = True
|
||||||
self.font_dim = {
|
self.font_dim = {
|
||||||
'xmin' : 0,
|
'xmin' : 0,
|
||||||
'ymin' : -self.sourceFont.descent,
|
'ymin' : -self.sourceFont.descent,
|
||||||
@ -1139,7 +1144,8 @@ class font_patcher:
|
|||||||
}
|
}
|
||||||
our_btb = self.sourceFont.descent + self.sourceFont.ascent
|
our_btb = self.sourceFont.descent + self.sourceFont.ascent
|
||||||
elif self.font_dim['height'] < 0:
|
elif self.font_dim['height'] < 0:
|
||||||
sys.exit("{}: Can not detect sane font height".format(projectName))
|
logger.critical("Can not detect sane font height")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Make all metrics equal
|
# Make all metrics equal
|
||||||
self.sourceFont.os2_typolinegap = 0
|
self.sourceFont.os2_typolinegap = 0
|
||||||
@ -1153,12 +1159,13 @@ class font_patcher:
|
|||||||
self.sourceFont.os2_use_typo_metrics = 1
|
self.sourceFont.os2_use_typo_metrics = 1
|
||||||
(check_hhea_btb, check_typo_btb, check_win_btb, _) = get_btb_metrics(self.sourceFont)
|
(check_hhea_btb, check_typo_btb, check_win_btb, _) = get_btb_metrics(self.sourceFont)
|
||||||
if check_hhea_btb != check_typo_btb or check_typo_btb != check_win_btb or check_win_btb != our_btb:
|
if check_hhea_btb != check_typo_btb or check_typo_btb != check_win_btb or check_win_btb != our_btb:
|
||||||
sys.exit("{}: Error in baseline to baseline code detected".format(projectName))
|
logger.critical("Error in baseline to baseline code detected")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Step 2
|
# Step 2
|
||||||
# Find the biggest char width and advance width
|
# Find the biggest char width and advance width
|
||||||
# 0x00-0x17f is the Latin Extended-A range
|
# 0x00-0x17f is the Latin Extended-A range
|
||||||
warned1 = self.args.quiet or self.args.nonmono # Do not warn if quiet or proportional target
|
warned1 = self.args.nonmono # Do not warn if proportional target
|
||||||
warned2 = warned1
|
warned2 = warned1
|
||||||
for glyph in range(0x21, 0x17f):
|
for glyph in range(0x21, 0x17f):
|
||||||
if glyph in range(0x7F, 0xBF) or glyph in [
|
if glyph in range(0x7F, 0xBF) or glyph in [
|
||||||
@ -1176,19 +1183,18 @@ class font_patcher:
|
|||||||
if self.font_dim['width'] < self.sourceFont[glyph].width:
|
if self.font_dim['width'] < self.sourceFont[glyph].width:
|
||||||
self.font_dim['width'] = self.sourceFont[glyph].width
|
self.font_dim['width'] = self.sourceFont[glyph].width
|
||||||
if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
|
if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
|
||||||
print("Warning: Extended glyphs wider than basic glyphs, results might be useless\n {}".format(
|
logger.debug("Extended glyphs wider than basic glyphs, results might be useless\n %s",
|
||||||
report_advance_widths(self.sourceFont)))
|
report_advance_widths(self.sourceFont))
|
||||||
warned1 = True
|
warned1 = True
|
||||||
# print("New MAXWIDTH-A {:X} {} -> {} {}".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']:
|
if xmax > self.font_dim['xmax']:
|
||||||
self.font_dim['xmax'] = xmax
|
self.font_dim['xmax'] = xmax
|
||||||
if not warned2 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
|
if not warned2 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
|
||||||
print("Info: Extended glyphs wider bounding box than basic glyphs")
|
logger.debug("Extended glyphs wider bounding box than basic glyphs")
|
||||||
warned2 = True
|
warned2 = True
|
||||||
# print("New MAXWIDTH-B {:X} {} -> {} {}".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))
|
||||||
if self.font_dim['width'] < self.font_dim['xmax']:
|
if self.font_dim['width'] < self.font_dim['xmax']:
|
||||||
if not self.args.quiet:
|
logger.debug("Font has negative right side bearing in extended glyphs")
|
||||||
print("Warning: Font has negative right side bearing in extended glyphs")
|
|
||||||
self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used
|
self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used
|
||||||
# print("FINAL", self.font_dim)
|
# print("FINAL", self.font_dim)
|
||||||
|
|
||||||
@ -1288,7 +1294,7 @@ class font_patcher:
|
|||||||
if sym_glyph.altuni:
|
if sym_glyph.altuni:
|
||||||
possible_codes += [ v for v, s, r in sym_glyph.altuni if v > currentSourceFontGlyph ]
|
possible_codes += [ v for v, s, r in sym_glyph.altuni if v > currentSourceFontGlyph ]
|
||||||
if len(possible_codes) == 0:
|
if len(possible_codes) == 0:
|
||||||
print(" Can not determine codepoint of {:X}. Skipping...".format(sym_glyph.unicode))
|
logger.warning("Can not determine codepoint of %X. Skipping...", sym_glyph.unicode)
|
||||||
continue
|
continue
|
||||||
currentSourceFontGlyph = min(possible_codes)
|
currentSourceFontGlyph = min(possible_codes)
|
||||||
else:
|
else:
|
||||||
@ -1311,9 +1317,8 @@ class font_patcher:
|
|||||||
# check if a glyph already exists in this location
|
# check if a glyph already exists in this location
|
||||||
if careful or 'careful' in sym_attr['params'] or currentSourceFontGlyph in self.essential:
|
if careful or 'careful' in sym_attr['params'] or currentSourceFontGlyph in self.essential:
|
||||||
if currentSourceFontGlyph in self.sourceFont:
|
if currentSourceFontGlyph in self.sourceFont:
|
||||||
if not self.args.quiet:
|
careful_type = 'essential' if currentSourceFontGlyph in self.essential else 'existing'
|
||||||
careful_type = 'essential' if currentSourceFontGlyph in self.essential else 'existing'
|
logger.debug("Found %s Glyph at %X. Skipping...", careful_type, currentSourceFontGlyph)
|
||||||
print(" Found {} Glyph at {:X}. Skipping...".format(careful_type, currentSourceFontGlyph))
|
|
||||||
# We don't want to touch anything so move to next Glyph
|
# We don't want to touch anything so move to next Glyph
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
@ -1461,8 +1466,8 @@ class font_patcher:
|
|||||||
if self.args.single:
|
if self.args.single:
|
||||||
(xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox()
|
(xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox()
|
||||||
if int(xmax - xmin) > self.font_dim['width'] * (1 + (overlap or 0)):
|
if int(xmax - xmin) > self.font_dim['width'] * (1 + (overlap or 0)):
|
||||||
print("\n Warning: Scaled glyph U+{:X} wider than one monospace width ({} / {} (overlap {}))".format(
|
logger.warning("Scaled glyph %X wider than one monospace width (%d / %d (overlap %f))",
|
||||||
currentSourceFontGlyph, int(xmax - xmin), self.font_dim['width'], overlap))
|
currentSourceFontGlyph, int(xmax - xmin), self.font_dim['width'], overlap)
|
||||||
|
|
||||||
# end for
|
# end for
|
||||||
|
|
||||||
@ -1603,7 +1608,7 @@ def half_gap(gap, top):
|
|||||||
gap_top = int(gap / 2)
|
gap_top = int(gap / 2)
|
||||||
gap_bottom = gap - gap_top
|
gap_bottom = gap - gap_top
|
||||||
if top:
|
if top:
|
||||||
print("Redistributing line gap of {} ({} top and {} bottom)".format(gap, gap_top, gap_bottom))
|
logger.info("Redistributing line gap of %d (%d top and %d bottom)", gap, gap_top, gap_bottom)
|
||||||
return gap_top
|
return gap_top
|
||||||
return gap_bottom
|
return gap_bottom
|
||||||
|
|
||||||
@ -1728,8 +1733,8 @@ def check_fontforge_min_version():
|
|||||||
|
|
||||||
# versions tested: 20150612, 20150824
|
# versions tested: 20150612, 20150824
|
||||||
if actualVersion < minimumVersion:
|
if actualVersion < minimumVersion:
|
||||||
sys.stderr.write("{}: You seem to be using an unsupported (old) version of fontforge: {}\n".format(projectName, actualVersion))
|
logger.critical("You seem to be using an unsupported (old) version of fontforge: %d", actualVersion)
|
||||||
sys.stderr.write("{}: Please use at least version: {}\n".format(projectName, minimumVersion))
|
logger.critical("Please use at least version: %d", minimumVersion)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def check_version_with_git(version):
|
def check_version_with_git(version):
|
||||||
@ -1777,7 +1782,6 @@ def setup_arguments():
|
|||||||
parser.add_argument('-s', '--mono', '--use-single-width-glyphs', dest='single', default=False, action='count', help='Whether to generate the glyphs as single-width not double-width (default is double-width)')
|
parser.add_argument('-s', '--mono', '--use-single-width-glyphs', dest='single', default=False, action='count', help='Whether to generate the glyphs as single-width not double-width (default is double-width)')
|
||||||
parser.add_argument('-l', '--adjust-line-height', dest='adjustLineHeight', default=False, action='store_true', help='Whether to adjust line heights (attempt to center powerline separators more evenly)')
|
parser.add_argument('-l', '--adjust-line-height', dest='adjustLineHeight', default=False, action='store_true', help='Whether to adjust line heights (attempt to center powerline separators more evenly)')
|
||||||
parser.add_argument('-q', '--quiet', '--shutup', dest='quiet', default=False, action='store_true', help='Do not generate verbose output')
|
parser.add_argument('-q', '--quiet', '--shutup', dest='quiet', default=False, action='store_true', help='Do not generate verbose output')
|
||||||
parser.add_argument('-w', '--windows', dest='windows', default=False, action='store_true', help='Limit the internal font name to 31 characters (for Windows compatibility)')
|
|
||||||
parser.add_argument('-c', '--complete', dest='complete', default=False, action='store_true', help='Add all available Glyphs')
|
parser.add_argument('-c', '--complete', dest='complete', default=False, action='store_true', help='Add all available Glyphs')
|
||||||
parser.add_argument('--careful', dest='careful', default=False, action='store_true', help='Do not overwrite existing glyphs if detected')
|
parser.add_argument('--careful', dest='careful', default=False, action='store_true', help='Do not overwrite existing glyphs if detected')
|
||||||
parser.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specificed in JSON configuration file')
|
parser.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specificed in JSON configuration file')
|
||||||
@ -1787,15 +1791,27 @@ def setup_arguments():
|
|||||||
parser.add_argument('-ext', '--extension', dest='extension', default="", type=str, nargs='?', help='Change font file type to create (e.g., ttf, otf)')
|
parser.add_argument('-ext', '--extension', dest='extension', default="", type=str, nargs='?', help='Change font file type to create (e.g., ttf, otf)')
|
||||||
parser.add_argument('-out', '--outputdir', dest='outputdir', default=".", type=str, nargs='?', help='The directory to output the patched font file to')
|
parser.add_argument('-out', '--outputdir', dest='outputdir', default=".", type=str, nargs='?', help='The directory to output the patched font file to')
|
||||||
parser.add_argument('--glyphdir', dest='glyphdir', default=__dir__ + "/src/glyphs/", type=str, nargs='?', help='Path to glyphs to be used for patching')
|
parser.add_argument('--glyphdir', dest='glyphdir', default=__dir__ + "/src/glyphs/", type=str, nargs='?', help='Path to glyphs to be used for patching')
|
||||||
parser.add_argument('--makegroups', dest='makegroups', default=False, action='store_true', help='Use alternative method to name patched fonts (experimental)')
|
parser.add_argument('--makegroups', dest='makegroups', default=1, type=int, nargs='?', help='Use alternative method to name patched fonts (recommended)', const=1, choices=range(0, 6 + 1))
|
||||||
|
# --makegroup has an additional undocumented numeric specifier. '--makegroup' is in fact '--makegroup 1'.
|
||||||
|
# Original font name: Hugo Sans Mono ExtraCondensed Light Italic
|
||||||
|
# NF Fam agg.
|
||||||
|
# 0 turned off, use old naming scheme [-] [-] [-]
|
||||||
|
# 1 HugoSansMono Nerd Font ExtraCondensed Light Italic [ ] [ ] [ ]
|
||||||
|
# 2 HugoSansMono Nerd Font ExtCn Light Italic [ ] [X] [ ]
|
||||||
|
# 3 HugoSansMono Nerd Font XCn Lt It [ ] [X] [X]
|
||||||
|
# 4 HugoSansMono NF ExtraCondensed Light Italic [X] [ ] [ ]
|
||||||
|
# 5 HugoSansMono NF ExtCn Light Italic [X] [X] [ ]
|
||||||
|
# 6 HugoSansMono NF XCn Lt It [X] [X] [X]
|
||||||
|
|
||||||
parser.add_argument('--variable-width-glyphs', dest='nonmono', default=False, action='store_true', help='Do not adjust advance width (no "overhang")')
|
parser.add_argument('--variable-width-glyphs', dest='nonmono', default=False, action='store_true', help='Do not adjust advance width (no "overhang")')
|
||||||
|
|
||||||
# progress bar arguments - https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse
|
# progress bar arguments - https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse
|
||||||
progressbars_group_parser = parser.add_mutually_exclusive_group(required=False)
|
progressbars_group_parser = parser.add_mutually_exclusive_group(required=False)
|
||||||
progressbars_group_parser.add_argument('--progressbars', dest='progressbars', action='store_true', help='Show percentage completion progress bars per Glyph Set')
|
progressbars_group_parser.add_argument('--progressbars', dest='progressbars', action='store_true', help='Show percentage completion progress bars per Glyph Set (default)')
|
||||||
progressbars_group_parser.add_argument('--no-progressbars', dest='progressbars', action='store_false', help='Don\'t show percentage completion progress bars per Glyph Set')
|
progressbars_group_parser.add_argument('--no-progressbars', dest='progressbars', action='store_false', help='Don\'t show percentage completion progress bars per Glyph Set')
|
||||||
parser.set_defaults(progressbars=True)
|
parser.set_defaults(progressbars=True)
|
||||||
parser.add_argument('--also-windows', dest='alsowindows', default=False, action='store_true', help='Create two fonts, the normal and the --windows version')
|
parser.add_argument('--debug', dest='debugmode', default=False, action='store_true', help='Verbose mode')
|
||||||
|
parser.add_argument('--dry', dest='dry_run', default=False, action='store_true', help='Do neither patch nor store the font, to check naming')
|
||||||
parser.add_argument('--xavgcharwidth', dest='xavgwidth', default=None, type=int, nargs='?', help='Adjust xAvgCharWidth (optional: concrete value)', const=True)
|
parser.add_argument('--xavgcharwidth', dest='xavgwidth', default=None, type=int, nargs='?', help='Adjust xAvgCharWidth (optional: concrete value)', const=True)
|
||||||
# --xavgcharwidth for compatibility with old applications like notepad and non-latin fonts
|
# --xavgcharwidth for compatibility with old applications like notepad and non-latin fonts
|
||||||
# Possible values with examples:
|
# Possible values with examples:
|
||||||
@ -1819,8 +1835,9 @@ def setup_arguments():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.makegroups and not FontnameParserOK:
|
if args.makegroups > 0 and not FontnameParserOK:
|
||||||
sys.exit("{}: FontnameParser module missing (bin/scripts/name_parser/Fontname*), can not --makegroups".format(projectName))
|
logger.critical("FontnameParser module missing (bin/scripts/name_parser/Fontname*), specify --makegroups 0")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# if you add a new font, set it to True here inside the if condition
|
# if you add a new font, set it to True here inside the if condition
|
||||||
if args.complete:
|
if args.complete:
|
||||||
@ -1853,24 +1870,23 @@ def setup_arguments():
|
|||||||
font_complete = False
|
font_complete = False
|
||||||
args.complete = font_complete
|
args.complete = font_complete
|
||||||
|
|
||||||
if args.alsowindows:
|
|
||||||
args.windows = False
|
|
||||||
|
|
||||||
if args.nonmono and args.single:
|
if args.nonmono and args.single:
|
||||||
print("Warning: Specified contradicting --variable-width-glyphs and --use-single-width-glyph. Ignoring --variable-width-glyphs.")
|
logging.warning("Specified contradicting --variable-width-glyphs and --use-single-width-glyph. Ignoring --variable-width-glyphs.")
|
||||||
args.nonmono = False
|
args.nonmono = False
|
||||||
|
|
||||||
make_sure_path_exists(args.outputdir)
|
make_sure_path_exists(args.outputdir)
|
||||||
if not os.path.isfile(args.font):
|
if not os.path.isfile(args.font):
|
||||||
sys.exit("{}: Font file does not exist: {}".format(projectName, args.font))
|
logging.critical("Font file does not exist: %s", args.font)
|
||||||
|
sys.exit(1)
|
||||||
if not os.access(args.font, os.R_OK):
|
if not os.access(args.font, os.R_OK):
|
||||||
sys.exit("{}: Can not open font file for reading: {}".format(projectName, args.font))
|
logging.critical("Can not open font file for reading: %s", args.font)
|
||||||
|
sys.exit(1)
|
||||||
is_ttc = len(fontforge.fontsInFile(args.font)) > 1
|
is_ttc = len(fontforge.fontsInFile(args.font)) > 1
|
||||||
try:
|
try:
|
||||||
source_font_test = TableHEADWriter(args.font)
|
source_font_test = TableHEADWriter(args.font)
|
||||||
args.is_variable = source_font_test.find_table([b'avar', b'cvar', b'fvar', b'gvarb', b'HVAR', b'MVAR', b'VVAR'], 0)
|
args.is_variable = source_font_test.find_table([b'avar', b'cvar', b'fvar', b'gvarb', b'HVAR', b'MVAR', b'VVAR'], 0)
|
||||||
if args.is_variable:
|
if args.is_variable:
|
||||||
print(" Warning: Source font is a variable open type font (VF), opening might fail...")
|
logging.warning("Source font is a variable open type font (VF), opening might fail...")
|
||||||
except:
|
except:
|
||||||
args.is_variable = False
|
args.is_variable = False
|
||||||
finally:
|
finally:
|
||||||
@ -1885,16 +1901,20 @@ def setup_arguments():
|
|||||||
args.extension = '.' + args.extension
|
args.extension = '.' + args.extension
|
||||||
if re.match("\.ttc$", args.extension, re.IGNORECASE):
|
if re.match("\.ttc$", args.extension, re.IGNORECASE):
|
||||||
if not is_ttc:
|
if not is_ttc:
|
||||||
sys.exit(projectName + ": Can not create True Type Collections from single font files")
|
logging.critical("Can not create True Type Collections from single font files")
|
||||||
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
if is_ttc:
|
if is_ttc:
|
||||||
sys.exit(projectName + ": Can not create single font files from True Type Collections")
|
logging.critical("Can not create single font files from True Type Collections")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if isinstance(args.xavgwidth, int) and not isinstance(args.xavgwidth, bool):
|
if isinstance(args.xavgwidth, int) and not isinstance(args.xavgwidth, bool):
|
||||||
if args.xavgwidth < 0:
|
if args.xavgwidth < 0:
|
||||||
sys.exit(projectName + ": --xavgcharwidth takes no negative numbers")
|
logging.critical("--xavgcharwidth takes no negative numbers")
|
||||||
|
sys.exit(2)
|
||||||
if args.xavgwidth > 16384:
|
if args.xavgwidth > 16384:
|
||||||
sys.exit(projectName + ": --xavgcharwidth takes only numbers up to 16384")
|
logging.critical("--xavgcharwidth takes only numbers up to 16384")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
@ -1902,24 +1922,43 @@ def setup_arguments():
|
|||||||
def main():
|
def main():
|
||||||
global version
|
global version
|
||||||
git_version = check_version_with_git(version)
|
git_version = check_version_with_git(version)
|
||||||
print("{} Patcher v{} ({}) (ff {}) executing".format(
|
allversions = "Patcher v{} ({}) (ff {})".format(
|
||||||
projectName, git_version if git_version else version, script_version, fontforge.version()))
|
git_version if git_version else version, script_version, fontforge.version())
|
||||||
|
print("{} {}".format(projectName, allversions))
|
||||||
if git_version:
|
if git_version:
|
||||||
version = git_version
|
version = git_version
|
||||||
check_fontforge_min_version()
|
check_fontforge_min_version()
|
||||||
args = setup_arguments()
|
args = setup_arguments()
|
||||||
|
|
||||||
|
global logger
|
||||||
|
logger = logging.getLogger(os.path.basename(args.font))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
f_handler = logging.FileHandler('font-patcher-log.txt')
|
||||||
|
f_handler.setFormatter(logging.Formatter('%(levelname)s: %(name)s %(message)s'))
|
||||||
|
logger.addHandler(f_handler)
|
||||||
|
logger.debug(allversions)
|
||||||
|
logger.debug("Options %s", repr(sys.argv[1:]))
|
||||||
|
c_handler = logging.StreamHandler(stream=sys.stdout)
|
||||||
|
c_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
|
||||||
|
if not args.debugmode:
|
||||||
|
c_handler.setLevel(logging.INFO)
|
||||||
|
logger.addHandler(c_handler)
|
||||||
|
logger.debug("Naming mode %d", args.makegroups)
|
||||||
|
|
||||||
patcher = font_patcher(args)
|
patcher = font_patcher(args)
|
||||||
|
|
||||||
sourceFonts = []
|
sourceFonts = []
|
||||||
all_fonts = fontforge.fontsInFile(args.font)
|
all_fonts = fontforge.fontsInFile(args.font)
|
||||||
for i, subfont in enumerate(all_fonts):
|
for i, subfont in enumerate(all_fonts):
|
||||||
if len(all_fonts) > 1:
|
if len(all_fonts) > 1:
|
||||||
print("\n{}: Processing {} ({}/{})".format(projectName, subfont, i + 1, len(all_fonts)))
|
print("\n")
|
||||||
|
logger.info("Processing %s (%d/%d)", subfont, i + 1, len(all_fonts))
|
||||||
try:
|
try:
|
||||||
sourceFonts.append(fontforge.open("{}({})".format(args.font, subfont), 1)) # 1 = ("fstypepermitted",))
|
sourceFonts.append(fontforge.open("{}({})".format(args.font, subfont), 1)) # 1 = ("fstypepermitted",))
|
||||||
except Exception:
|
except Exception:
|
||||||
sys.exit("{}: Can not open font '{}', try to open with fontforge interactively to get more information".format(
|
logger.critical("Can not open font '%s', try to open with fontforge interactively to get more information",
|
||||||
projectName, subfont))
|
subfont)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
patcher.patch(sourceFonts[-1])
|
patcher.patch(sourceFonts[-1])
|
||||||
|
|
||||||
@ -1928,13 +1967,6 @@ def main():
|
|||||||
patcher.setup_font_names(f)
|
patcher.setup_font_names(f)
|
||||||
patcher.generate(sourceFonts)
|
patcher.generate(sourceFonts)
|
||||||
|
|
||||||
# This mainly helps to improve CI runtime
|
|
||||||
if patcher.args.alsowindows:
|
|
||||||
patcher.args.windows = True
|
|
||||||
for f in sourceFonts:
|
|
||||||
patcher.setup_font_names(f)
|
|
||||||
patcher.generate(sourceFonts)
|
|
||||||
|
|
||||||
for f in sourceFonts:
|
for f in sourceFonts:
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
1
src/unpatched-fonts/3270/config.cfg
Normal file
1
src/unpatched-fonts/3270/config.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 2"
|
@ -1,3 +1,3 @@
|
|||||||
config_rfn="Cascadia Code"
|
config_rfn="Cascadia Code"
|
||||||
config_rfn_substitue="Caskaydia Cove"
|
config_rfn_substitue="Caskaydia Cove"
|
||||||
config_patch_flags="--makegroups"
|
config_patch_flags="--makegroups 4"
|
||||||
|
@ -1 +1,2 @@
|
|||||||
config_has_powerline=1
|
config_has_powerline=1
|
||||||
|
config_patch_flags="--makegroups 2"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
config_has_powerline=1
|
config_has_powerline=1
|
||||||
config_rfn=Hasklig
|
config_rfn=Hasklig
|
||||||
config_rfn_substitue=Hasklug
|
config_rfn_substitue=Hasklug
|
||||||
|
config_patch_flags="--makegroups 2"
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
config_has_powerline=1
|
config_has_powerline=1
|
||||||
config_patch_flags="--makegroups"
|
config_patch_flags="--makegroups 4"
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
config_has_powerline=1
|
config_has_powerline=1
|
||||||
config_patch_flags="--makegroups"
|
config_patch_flags="--makegroups 4"
|
||||||
|
@ -1 +1 @@
|
|||||||
config_patch_flags="--makegroups"
|
config_patch_flags="--makegroups 4"
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 3"
|
1
src/unpatched-fonts/MPlus/config.cfg
Normal file
1
src/unpatched-fonts/MPlus/config.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 2"
|
@ -1 +0,0 @@
|
|||||||
config_patch_flags="--makegroups"
|
|
1
src/unpatched-fonts/Noto/config.cfg
Normal file
1
src/unpatched-fonts/Noto/config.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 5"
|
1
src/unpatched-fonts/Overpass/config.cfg
Normal file
1
src/unpatched-fonts/Overpass/config.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 2"
|
1
src/unpatched-fonts/RobotoMono/config.cfg
Normal file
1
src/unpatched-fonts/RobotoMono/config.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 3"
|
@ -1,3 +1,4 @@
|
|||||||
config_has_powerline=1
|
config_has_powerline=1
|
||||||
config_rfn=Source
|
config_rfn=Source
|
||||||
config_rfn_substitue=Sauce
|
config_rfn_substitue=Sauce
|
||||||
|
config_patch_flags="--makegroups 4"
|
||||||
|
@ -1 +1 @@
|
|||||||
config_has_powerline=0
|
config_patch_flags="--makegroups 2"
|
||||||
|
@ -1 +1 @@
|
|||||||
config_has_powerline=0
|
config_patch_flags="--makegroups 2"
|
||||||
|
1
src/unpatched-fonts/VictorMono/config.cfg
Normal file
1
src/unpatched-fonts/VictorMono/config.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config_patch_flags="--makegroups 4"
|
@ -1,2 +1,5 @@
|
|||||||
# iA-Fonts
|
# iA Writer 2.000
|
||||||
These are fonts from iA. Please read the licensing files before using them in any way.
|
These are fonts from iA. Duo and Quattro are almost monospaced but allow more room for some letters.
|
||||||
|
See http://ia.net/topics/in-search-of-the-perfect-writing-font/
|
||||||
|
|
||||||
|
For more information have a look at the upstream website: https://github.com/iaolo/iA-Fonts
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,100 +0,0 @@
|
|||||||
# iA Writer Typeface
|
|
||||||
|
|
||||||
Copyright © 2018 Information Architects Inc. with Reserved Font Name "iA Writer"
|
|
||||||
|
|
||||||
# Based on IBM Plex Typeface
|
|
||||||
|
|
||||||
Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
|
|
||||||
|
|
||||||
# License
|
|
||||||
|
|
||||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
||||||
This license is copied below, and is also available with a FAQ at:
|
|
||||||
http://scripts.sil.org/OFL
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
|
||||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
PREAMBLE
|
|
||||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
||||||
development of collaborative font projects, to support the font creation
|
|
||||||
efforts of academic and linguistic communities, and to provide a free and
|
|
||||||
open framework in which fonts may be shared and improved in partnership
|
|
||||||
with others.
|
|
||||||
|
|
||||||
The OFL allows the licensed fonts to be used, studied, modified and
|
|
||||||
redistributed freely as long as they are not sold by themselves. The
|
|
||||||
fonts, including any derivative works, can be bundled, embedded,
|
|
||||||
redistributed and/or sold with any software provided that any reserved
|
|
||||||
names are not used by derivative works. The fonts and derivatives,
|
|
||||||
however, cannot be released under any other type of license. The
|
|
||||||
requirement for fonts to remain under this license does not apply
|
|
||||||
to any document created using the fonts or their derivatives.
|
|
||||||
|
|
||||||
DEFINITIONS
|
|
||||||
"Font Software" refers to the set of files released by the Copyright
|
|
||||||
Holder(s) under this license and clearly marked as such. This may
|
|
||||||
include source files, build scripts and documentation.
|
|
||||||
|
|
||||||
"Reserved Font Name" refers to any names specified as such after the
|
|
||||||
copyright statement(s).
|
|
||||||
|
|
||||||
"Original Version" refers to the collection of Font Software components as
|
|
||||||
distributed by the Copyright Holder(s).
|
|
||||||
|
|
||||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
||||||
or substituting -- in part or in whole -- any of the components of the
|
|
||||||
Original Version, by changing formats or by porting the Font Software to a
|
|
||||||
new environment.
|
|
||||||
|
|
||||||
"Author" refers to any designer, engineer, programmer, technical
|
|
||||||
writer or other person who contributed to the Font Software.
|
|
||||||
|
|
||||||
PERMISSION & CONDITIONS
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
||||||
redistribute, and sell modified and unmodified copies of the Font
|
|
||||||
Software, subject to the following conditions:
|
|
||||||
|
|
||||||
1) Neither the Font Software nor any of its individual components,
|
|
||||||
in Original or Modified Versions, may be sold by itself.
|
|
||||||
|
|
||||||
2) Original or Modified Versions of the Font Software may be bundled,
|
|
||||||
redistributed and/or sold with any software, provided that each copy
|
|
||||||
contains the above copyright notice and this license. These can be
|
|
||||||
included either as stand-alone text files, human-readable headers or
|
|
||||||
in the appropriate machine-readable metadata fields within text or
|
|
||||||
binary files as long as those fields can be easily viewed by the user.
|
|
||||||
|
|
||||||
3) No Modified Version of the Font Software may use the Reserved Font
|
|
||||||
Name(s) unless explicit written permission is granted by the corresponding
|
|
||||||
Copyright Holder. This restriction only applies to the primary font name as
|
|
||||||
presented to the users.
|
|
||||||
|
|
||||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
||||||
Software shall not be used to promote, endorse or advertise any
|
|
||||||
Modified Version, except to acknowledge the contribution(s) of the
|
|
||||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
5) The Font Software, modified or unmodified, in part or in whole,
|
|
||||||
must be distributed entirely under this license, and must not be
|
|
||||||
distributed under any other license. The requirement for fonts to
|
|
||||||
remain under this license does not apply to any document created
|
|
||||||
using the Font Software.
|
|
||||||
|
|
||||||
TERMINATION
|
|
||||||
This license becomes null and void if any of the above conditions are
|
|
||||||
not met.
|
|
||||||
|
|
||||||
DISCLAIMER
|
|
||||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
||||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
||||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
||||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -1,11 +0,0 @@
|
|||||||
iA Writer Duospace comes bundled with [iA Writer for Mac and iOS](https://ia.net/writer/buy/)
|
|
||||||
|
|
||||||
For in depth explanation of iA Writer Duospace please read our [blog entry](http://ia.net/topics/in-search-of-the-perfect-writing-font/)
|
|
||||||
|
|
||||||
This is a modification of IBM's Plex font.
|
|
||||||
The upstream project is [here](https://github.com/IBM/type)
|
|
||||||
|
|
||||||
As required by IBM, we named it differently.
|
|
||||||
Please read the licensing file before working with it.
|
|
||||||
|
|
||||||
If you fork or reuse our version, please reference us, too.
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user