-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
336 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,316 @@ | ||
diff --git a/font-patcher b/font-patcher | ||
index 51e3ff1..f639f3f 100755 | ||
--- a/font-patcher | ||
+++ b/font-patcher | ||
@@ -13,6 +13,14 @@ projectName = "Nerd Fonts" | ||
projectNameAbbreviation = "NF" | ||
projectNameSingular = projectName[:-1] | ||
|
||
+# FOR SARASA | ||
+projectName = "Nerds" | ||
+projectNameAbbreviation = "" | ||
+projectNameSingular = projectName[:-1] | ||
+subFamily = "" | ||
+looseName = "Sarasa Term SC Nerd" | ||
+compactName = "SarasaTermSCNerd" | ||
+ | ||
import sys | ||
import re | ||
import os | ||
@@ -187,7 +195,10 @@ def check_panose_monospaced(font): | ||
return -1 # invalid Panose info | ||
panose_mono = ((panose[0] == 2 and panose[3] == 9) or | ||
(panose[0] == 3 and panose[3] == 3)) | ||
- return 1 if panose_mono else 0 | ||
+ | ||
+ # FOR SARASA | ||
+ return 1 | ||
+ # return 1 if panose_mono else 0 | ||
|
||
def panose_check_to_text(value, panose = False): | ||
""" Convert value from check_panose_monospaced() to human readable string """ | ||
@@ -208,6 +219,10 @@ def panose_proportion_to_text(value): | ||
def is_monospaced(font): | ||
""" Check if a font is probably monospaced """ | ||
# Some fonts lie (or have not any Panose flag set), spot check monospaced: | ||
+ | ||
+ # FOR SARASA | ||
+ return (True, None) | ||
+ | ||
width = -1 | ||
width_mono = True | ||
for glyph in [ 0x49, 0x4D, 0x57, 0x61, 0x69, 0x6d, 0x2E ]: # wide and slim glyphs 'I', 'M', 'W', 'a', 'i', 'm', '.' | ||
@@ -448,6 +463,13 @@ class font_patcher: | ||
outfile = os.path.normpath(os.path.join( | ||
sanitize_filename(self.args.outputdir, True), | ||
sanitize_filename(fontname) + self.args.extension)) | ||
+ | ||
+ # FOR SARASA | ||
+ outfile = os.path.normpath(os.path.join( | ||
+ sanitize_filename(self.args.outputdir, True), | ||
+ f'{compactName}-{self.get_subfamily()}.ttf' | ||
+ )) | ||
+ | ||
bitmaps = str() | ||
if len(sourceFont.bitmapSizes): | ||
logger.debug("Preserving bitmaps %s", repr(sourceFont.bitmapSizes)) | ||
@@ -505,6 +527,10 @@ class font_patcher: | ||
logger.critical("Source font is a variable open type font (VF) and the patch results will most likely not be what you want") | ||
print(message) | ||
|
||
+ # FOR SARASA: build hdmx table | ||
+ print("Building hdmx table and fix post table") | ||
+ post_fix(self.args.font, outfile) | ||
+ | ||
if self.args.postprocess: | ||
subprocess.call([self.args.postprocess, outfile]) | ||
print("\n") | ||
@@ -558,6 +584,10 @@ class font_patcher: | ||
additionalFontNameSuffix += " WEA" | ||
verboseAdditionalFontNameSuffix += " Plus Weather Icons" | ||
|
||
+ # FOR SARASA: clean file name | ||
+ additionalFontNameSuffix = "" + projectNameSingular | ||
+ verboseAdditionalFontNameSuffix = "" + projectNameSingular | ||
+ | ||
# add mono signifier to beginning of name suffix | ||
if self.args.single: | ||
variant_abbrev = "M" | ||
@@ -569,12 +599,20 @@ class font_patcher: | ||
variant_abbrev = "" | ||
variant_full = "" | ||
|
||
+ # FOR SARASA: clean file name | ||
+ variant_abbrev = "" | ||
+ variant_full = "" | ||
+ | ||
ps_suffix = projectNameAbbreviation + variant_abbrev + additionalFontNameSuffix | ||
|
||
# add 'Nerd Font' to beginning of name suffix | ||
verboseAdditionalFontNameSuffix = " " + projectNameSingular + variant_full + verboseAdditionalFontNameSuffix | ||
additionalFontNameSuffix = " " + projectNameSingular + variant_full + additionalFontNameSuffix | ||
|
||
+ # FOR SARASA: clean file name | ||
+ additionalFontNameSuffix = "" + projectNameSingular | ||
+ verboseAdditionalFontNameSuffix = "" + projectNameSingular | ||
+ | ||
if FontnameParserOK and self.args.makegroups > 0: | ||
user_supplied_name = False # User supplied names are kept unchanged | ||
if not isinstance(self.args.force_name, str): | ||
@@ -623,6 +661,10 @@ class font_patcher: | ||
# dont trust 'font.familyname' | ||
familyname = fontname | ||
|
||
+ # FOR SARASA | ||
+ familyname = looseName | ||
+ fallbackStyle = self.get_subfamily() | ||
+ | ||
# fullname (filename) can always use long/verbose font name, even in windows | ||
if font.fullname != None: | ||
fullname = font.fullname + verboseAdditionalFontNameSuffix | ||
@@ -725,12 +767,14 @@ class font_patcher: | ||
'Powerline': '' | ||
} | ||
|
||
+ # FOR SARASA | ||
projectInfo = ( | ||
- "Patched with '" + projectName + " Patcher' (https://github.com/ryanoasis/nerd-fonts)\n\n" | ||
+ # "Patched with '" + projectName + " Patcher' (https://github.com/ryanoasis/nerd-fonts)\n\n" | ||
+ "Patched with 'Sarasa Term SC Nerd Patcher' (https://github.com/laishulu/Sarasa-Term-SC-Nerd)\n\n" | ||
"* Website: https://www.nerdfonts.com\n" | ||
"* Version: " + version + "\n" | ||
- "* Development Website: https://github.com/ryanoasis/nerd-fonts\n" | ||
- "* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/-/changelog.md" | ||
+ # "* Development Website: https://github.com/ryanoasis/nerd-fonts\n" | ||
+ # "* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/-/changelog.md" | ||
) | ||
|
||
familyname = replace_font_name(familyname, reservedFontNameReplacements) | ||
@@ -763,6 +807,29 @@ class font_patcher: | ||
n.inject_suffix(verboseAdditionalFontNameSuffix, ps_suffix, short_family) | ||
n.rename_font(font) | ||
|
||
+ | ||
+ # FOR SARASA | ||
+ font.familyname = looseName | ||
+ subFamily = self.get_subfamily() | ||
+ font.fullname = f"{looseName} {en_subfamily(subFamily)}" | ||
+ font.fontname = f"{compactName}-{subFamily}" | ||
+ uniqueID = f"{font.fullname}; Sarasa v{self.sourceFont.version}" | ||
+ | ||
+ font.appendSFNTName(str("English (US)"), str("UniqueID"), uniqueID) | ||
+ font.appendSFNTName(str("Chinese (PRC)"), str("UniqueID"), uniqueID) | ||
+ font.appendSFNTName(str('English (US)'), str('Fullname'), font.fullname) | ||
+ font.appendSFNTName(str("Chinese (PRC)"), str("Fullname"), zh_family(font.fullname)) | ||
+ | ||
+ font.appendSFNTName(str('English (US)'), str('Family'), font.familyname) | ||
+ font.appendSFNTName(str('Chinese (PRC)'), str('Family'), zh_family(font.familyname)) | ||
+ font.appendSFNTName(str('English (US)'), str('SubFamily'), en_subfamily(subFamily)) | ||
+ font.appendSFNTName(str('Chinese (PRC)'), str('SubFamily'), zh_subfamily(subFamily)) | ||
+ | ||
+ font.appendSFNTName(str('English (US)'), str('Preferred Family'), font.familyname) | ||
+ font.appendSFNTName(str('Chinese (PRC)'), str('Preferred Family'), zh_family(font.familyname)) | ||
+ font.appendSFNTName(str('English (US)'), str('Preferred Styles'), en_subfamily(subFamily)) | ||
+ font.appendSFNTName(str('Chinese (PRC)'), str('Preferred Styles'), zh_subfamily(subFamily)) | ||
+ | ||
font.comment = projectInfo | ||
font.fontlog = projectInfo | ||
|
||
@@ -776,6 +843,10 @@ class font_patcher: | ||
self.sourceFont.version = str(self.sourceFont.cidversion) + ";" + projectName + " " + version | ||
self.sourceFont.sfntRevision = None # Auto-set (refreshed) by fontforge | ||
self.sourceFont.appendSFNTName(str('English (US)'), str('Version'), "Version " + self.sourceFont.version) | ||
+ | ||
+ # FOR SARASA: set version | ||
+ self.sourceFont.appendSFNTName(str('Chinese (PRC)'), str('Version'), "版本 " + self.sourceFont.version) | ||
+ | ||
# The Version SFNT name is later reused by the NameParser for UniqueID | ||
# print("Version now is {}".format(sourceFont.version)) | ||
|
||
@@ -842,7 +913,6 @@ class font_patcher: | ||
if width_mono: | ||
force_panose_monospaced(self.sourceFont) | ||
|
||
- | ||
def setup_patch_set(self): | ||
""" Creates list of dicts to with instructions on copying glyphs from each symbol font into self.sourceFont """ | ||
|
||
@@ -1139,7 +1209,21 @@ class font_patcher: | ||
{'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x23FB, 'SymEnd': 0x23FE, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Power, Power On/Off, Power On, Sleep | ||
{'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x2B58, 'SymEnd': 0x2B58, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Heavy Circle (aka Power Off) | ||
{'Enabled': False , 'Name': "Material legacy", 'Filename': "materialdesign/materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, | ||
- {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF1AF0,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ # FOR SARASA | ||
+ # {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF1AF0,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ # {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF165C,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF0553,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0565,'SymEnd': 0xF0E32,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0E40,'SymEnd': 0xF0E85,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0E8E,'SymEnd': 0xF118E,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF119E,'SymEnd': 0xF11AE,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF11E3,'SymEnd': 0xF126F,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF129E,'SymEnd': 0xF13ED,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF13FE,'SymEnd': 0xF149F,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF14B0,'SymEnd': 0xF14CF,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF14DE,'SymEnd': 0xF165C,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF19E8,'SymEnd': 0xF19FD,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
+ | ||
{'Enabled': self.args.weather, 'Name': "Weather Icons", 'Filename': "weather-icons/weathericons-regular-webfont.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF0EB, 'SrcStart': 0xE300, 'ScaleRules': WEATH_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, | ||
{'Enabled': self.args.fontlogos, 'Name': "Font Logos", 'Filename': "font-logos.ttf", 'Exact': True, 'SymStart': 0xF300, 'SymEnd': 0xF381, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, | ||
{'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass | ||
@@ -1253,6 +1337,10 @@ class font_patcher: | ||
|
||
self.font_dim = {'xmin': 0, 'ymin': 0, 'xmax': 0, 'ymax': 0, 'width' : 0, 'height': 0, 'iconheight': 0, 'ypadding': 0} | ||
|
||
+ # FOR SARASA | ||
+ self.font_dim = {'xmin': 0, 'ymin': 0, 'xmax': 0, 'ymax': 0, 'width' : 0, 'height': 0, 'iconheight': 0, 'ypadding': 0, 'em': 0} | ||
+ self.font_dim['em'] = self.sourceFont.em | ||
+ | ||
if metrics == Metric.HHEA: | ||
self.font_dim['ymin'] = self.sourceFont.hhea_descent - half_gap(self.sourceFont.hhea_linegap, False) | ||
self.font_dim['ymax'] = self.sourceFont.hhea_ascent + half_gap(self.sourceFont.hhea_linegap, True) | ||
@@ -1361,9 +1449,13 @@ class font_patcher: | ||
""" Get the target width (1 or 2 'cell') for a given stretch parameter """ | ||
# For monospaced fonts all chars need to be maximum 'one' space wide | ||
# other fonts allows double width glyphs for 'pa' or if requested with '2' | ||
- if self.args.single or ('pa' not in stretch and '2' not in stretch) or '1' in stretch: | ||
- return 1 | ||
- return 2 | ||
+ | ||
+ # FOR SARASA | ||
+ return 1 | ||
+ | ||
+ # if self.args.single or ('pa' not in stretch and '2' not in stretch) or '1' in stretch: | ||
+ # return 1 | ||
+ # return 2 | ||
|
||
def get_scale_factors(self, sym_dim, stretch, overlap=None): | ||
""" Get scale in x and y as tuple """ | ||
@@ -1791,6 +1883,10 @@ class font_patcher: | ||
return (scale, box) | ||
return None | ||
|
||
+ # FOR SARASA: extract subFamily from font name | ||
+ def get_subfamily(self): | ||
+ file_name = self.args.font.split('.')[-2] | ||
+ return file_name.split('-')[-1] | ||
|
||
def half_gap(gap, top): | ||
""" Divides integer value into two new integers """ | ||
@@ -2210,6 +2306,76 @@ def main(): | ||
for f in sourceFonts: | ||
f.close() | ||
|
||
+def zh_family(name): | ||
+ res = name.replace(looseName, "更纱终端书呆黑体-简") | ||
+ res = res.replace(compactName, "更纱终端书呆黑体-简") | ||
+ return res | ||
+ | ||
+def en_subfamily(compact): | ||
+ return compact.replace("Italic", " Italic").strip() | ||
+ | ||
+def zh_subfamily(compact): | ||
+ sub_family_dict = { | ||
+ "ExtraLight": "特细体", | ||
+ "ExtraLightItalic":"特细斜体", | ||
+ "Light":"细体", | ||
+ "LightItalic":"细斜体", | ||
+ "Regular":"常规体", | ||
+ "Italic":"斜体", | ||
+ "SemiBold":"中粗体", | ||
+ "SemiBoldItalic":"中粗斜体", | ||
+ "Bold":"粗体", | ||
+ "BoldItalic":"粗斜体" | ||
+ } | ||
+ return sub_family_dict[compact] | ||
+ | ||
+# FOR SARASA: build hdmx table | ||
+import sys | ||
+import math | ||
+from fontTools.ttLib import TTFont, newTable | ||
+ | ||
+def post_fix(src_file, dst_file): | ||
+ dst_font = TTFont(dst_file, recalcBBoxes=False) | ||
+ build_hdmx(dst_font) | ||
+ fix_isFixedPitch(dst_font) | ||
+ | ||
+ src_font = TTFont(src_file) | ||
+ dst_font["OS/2"].xAvgCharWidth = src_font["OS/2"].xAvgCharWidth | ||
+ src_font.close() | ||
+ | ||
+ dst_font.save(dst_file) | ||
+ dst_font.close() | ||
+ | ||
+def build_hdmx(font): | ||
+ headFlagInstructionsMayAlterAdvanceWidth = 0x0010 | ||
+ sarasaHintPpemMin = 11 | ||
+ sarasaHintPpemMax = 48 | ||
+ | ||
+ originalFontHead = font["head"] | ||
+ originalFontHmtx = font["hmtx"] | ||
+ | ||
+ originalFontHead.flags |= headFlagInstructionsMayAlterAdvanceWidth | ||
+ | ||
+ hdmxTable = newTable("hdmx") | ||
+ hdmxTable.hdmx = {} | ||
+ | ||
+ # build hdmx table for odd and hinted ppems only. | ||
+ for ppem in range( | ||
+ math.floor(sarasaHintPpemMin / 2) * 2 + 1, sarasaHintPpemMax + 1, 2 | ||
+ ): | ||
+ halfUpm = originalFontHead.unitsPerEm / 2 | ||
+ halfPpem = math.ceil(ppem / 2) | ||
+ hdmxTable.hdmx[ppem] = { | ||
+ name: math.ceil(width / halfUpm) * halfPpem | ||
+ for name, (width, _) in originalFontHmtx.metrics.items() | ||
+ } | ||
+ | ||
+ font["hdmx"] = hdmxTable | ||
+ | ||
+def fix_isFixedPitch(font): | ||
+ post = font["post"].__dict__ | ||
+ post["isFixedPitch"] = 1 | ||
+ | ||
|
||
if __name__ == "__main__": | ||
__dir__ = os.path.dirname(os.path.abspath(__file__)) |
Oops, something went wrong.