diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bccad9c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +# MIT License + +# Copyright (c) 2021 FollieHiyuki + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. diff --git a/README.md b/README.md index 9fc8101..892b9ba 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,27 @@ -## nerd-fonts +# nerd-fonts -This repository contains necessary files for building your own Nerd-fonts. All of them are pulled directly from the original repository. +This repository contains necessary files for building your own Nerd-fonts. -### Why? +## Why? [Nerd fonts repository](https://github.com/ryanoasis/nerd-fonts) is 6GB in size, which is a pain to clone if all you need is patching your own fonts. -### Usage +## Usage -You need `fontforge` installed. Clone this repository, then: +You need `fontforge` and `fonttools` installed. Clone this repository, then: ```bash cd nerd-fonts -# Update the files if needed (need `curl`) +# Update the files if needed (need `curl` and 'bash') ./update.sh # Patch your font -./font-patcher -c path-to-your-original-font.ttf +fontforge -script font-patcher --careful --complete path-to-your-original-font.ttf ``` -### License +## License -- `update.sh` is licensed under MIT -- The other files fall under their original licenses +- The python scripts are taken from +- The files downloaded with `update.sh` fall under their original licenses +- Other are MIT diff --git a/build-hdmx-for-sarasa.py b/build-hdmx-for-sarasa.py new file mode 100644 index 0000000..9ad316d --- /dev/null +++ b/build-hdmx-for-sarasa.py @@ -0,0 +1,49 @@ +#! /usr/bin/python + +# credit: https://github.com/be5invis/Sarasa-Gothic/issues/108#issuecomment-517240248 + +# usage: +# python build-hdmx-for-sarasa.py your-sarasa-font.ttf + +import sys +import math + +from fontTools.ttLib import TTFont, newTable + + +def main(): + headFlagInstructionsMayAlterAdvanceWidth = 0x0010 + sarasaHintPpemMin = 11 + sarasaHintPpemMax = 48 + + filename = sys.argv[1] + + font = TTFont(filename, recalcBBoxes=False) + + 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 + + font.save(filename) + font.close() + + +if __name__ == "__main__": + main() diff --git a/correct-ttf-font-family-name.py b/correct-ttf-font-family-name.py new file mode 100644 index 0000000..2a5360f --- /dev/null +++ b/correct-ttf-font-family-name.py @@ -0,0 +1,61 @@ +#! /usr/bin/python + +# usage: +# python correct-ttf-font-family-name.py filename.ttf + +import sys + +from fontTools.ttLib import TTFont + + +def main(): + filename = sys.argv[1] + + font = TTFont(filename, recalcBBoxes=False) + fontName = font["name"] + + originalFontUniqueID = fontName.getName(3, 1, 0, 0).toUnicode() + originalFontFullname = fontName.getName(4, 1, 0, 0).toUnicode() + originalFontPreferredStyle = fontName.getName(17, 1, 0, 0).toUnicode() + + for entry in fontName.names: + nameID = entry.nameID + platformID = entry.platformID + platEncID = entry.platEncID + langID = entry.langID + + if langID in [1028, 1041, 2052, 3076]: + string = ( + entry.toUnicode() + .replace(" CL", " CL Nerd Font") + .replace(" TC", " TC Nerd Font") + .replace(" J", " J Nerd Font") + .replace(" SC", " SC Nerd Font") + .replace(" HC", " HC Nerd Font") + ) + fontName.setName(string, nameID, platformID, platEncID, langID) + + elif nameID in [1, 16]: + string = originalFontUniqueID.replace( + f" {originalFontPreferredStyle}", " Nerd Font" + ) + fontName.setName(string, nameID, platformID, platEncID, langID) + + elif nameID == 3: + string = originalFontUniqueID.replace( + f" {originalFontPreferredStyle}", + f" Nerd Font {originalFontPreferredStyle}", + ) + fontName.setName(string, nameID, platformID, platEncID, langID) + + elif nameID == 6: + fontName.setName( + originalFontFullname, nameID, platformID, platEncID, langID + ) + + font.save(filename) + font.close() + + +if __name__ == "__main__": + main() diff --git a/font-patcher b/font-patcher index 2d96629..9440b2a 100755 --- a/font-patcher +++ b/font-patcher @@ -51,7 +51,14 @@ class font_patcher: self.extension = "" self.setup_arguments() self.config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True) - self.sourceFont = fontforge.open(self.args.font) + if not os.path.isfile(self.args.font): + sys.exit("{}: Font file does not exist: {}".format(projectName, self.args.font)) + if not os.access(self.args.font, os.R_OK): + sys.exit("{}: Can not open font file for reading: {}".format(projectName, self.args.font)) + try: + self.sourceFont = fontforge.open(self.args.font, 1) # 1 = ("fstypepermitted",)) + except Exception: + sys.exit(projectName + ": Can not open font, try to open with fontforge interactively to get more information") self.setup_font_names() self.remove_ligatures() make_sure_path_exists(self.args.outputdir) @@ -62,16 +69,26 @@ class font_patcher: self.sourceFont.encoding = 'UnicodeFull' # Update the font encoding to ensure that the Unicode glyphs are available self.onlybitmaps = self.sourceFont.onlybitmaps # Fetch this property before adding outlines. NOTE self.onlybitmaps initialized and never used if self.args.extension == "": - self.extension = os.path.splitext(self.sourceFont.path)[1] + self.extension = os.path.splitext(self.args.font)[1] else: self.extension = '.' + self.args.extension def patch(self): + + print("{} Patcher v{} executing\n".format(projectName, version)) + if self.args.single: # Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows. # This needs to be done on all characters, as some information seems to be lost from the original font file. self.set_sourcefont_glyph_widths() + # For some Windows applications (e.g. 'cmd') that is not enough. But they seem to honour the Panose table + # https://forum.high-logic.com/postedfiles/Panose.pdf + panose = list(self.sourceFont.os2_panose) + if panose[0] == 0 or panose[0] == 2: # 0 (1st value) = family kind; 0 = any (default); 2 = latin text and display + panose[0] = 2 # Assert kind + panose[3] = 9 # 3 (4th value) = propotion; 9 = monospaced + self.sourceFont.os2_panose = tuple(panose) # Prevent opening and closing the fontforge font. Makes things faster when patching # multiple ranges using the same symbol font. @@ -157,6 +174,7 @@ class font_patcher: sym_font_group.add_argument('--fontawesomeextension', dest='fontawesomeextension', default=False, action='store_true', help='Add Font Awesome Extension Glyphs (https://andrelzgava.github.io/font-awesome-extension/)') sym_font_group.add_argument('--fontlinux', '--fontlogos', dest='fontlinux', default=False, action='store_true', help='Add Font Linux and other open source Glyphs (https://github.com/Lukas-W/font-logos)') sym_font_group.add_argument('--octicons', dest='octicons', default=False, action='store_true', help='Add Octicons Glyphs (https://octicons.github.com)') + sym_font_group.add_argument('--codicons', dest='codicons', default=False, action='store_true', help='Add Codicons Glyphs (https://github.com/microsoft/vscode-codicons)') sym_font_group.add_argument('--powersymbols', dest='powersymbols', default=False, action='store_true', help='Add IEC Power Symbols (https://unicodepowersymbol.com/)') sym_font_group.add_argument('--pomicons', dest='pomicons', default=False, action='store_true', help='Add Pomicon Glyphs (https://github.com/gabrielelana/pomicons)') sym_font_group.add_argument('--powerline', dest='powerline', default=False, action='store_true', help='Add Powerline Glyphs') @@ -172,6 +190,7 @@ class font_patcher: self.args.fontawesomeextension = True self.args.fontlinux = True self.args.octicons = True + self.args.codicons = True self.args.powersymbols = True self.args.pomicons = True self.args.powerline = True @@ -235,6 +254,9 @@ class font_patcher: if self.args.powersymbols: additionalFontNameSuffix += " PS" verboseAdditionalFontNameSuffix += " Plus Power Symbols" + if self.args.codicons: + additionalFontNameSuffix += " C" + verboseAdditionalFontNameSuffix += " Plus Codicons" if self.args.pomicons: additionalFontNameSuffix += " P" verboseAdditionalFontNameSuffix += " Plus Pomicons" @@ -351,7 +373,15 @@ class font_patcher: 'Cascadia Mono' : 'Caskaydia Mono', 'cascadia mono' : 'caskaydia mono', 'CascadiaMono' : 'CaskaydiaMono', - 'cascadiamono' : 'caskaydiamono' + 'cascadiamono' : 'caskaydiamono', + 'Fira Mono' : 'Fura Mono', + 'Fira Sans' : 'Fura Sans', + 'FiraMono' : 'FuraMono', + 'FiraSans' : 'FuraSans', + 'fira mono' : 'fura mono', + 'fira sans' : 'fura sans', + 'firamono' : 'furamono', + 'firasans' : 'furasans', } # remove overly verbose font names @@ -395,12 +425,13 @@ class font_patcher: self.sourceFont.comment = projectInfo self.sourceFont.fontlog = projectInfo - # TODO version not being set for all font types (e.g. ttf) # print("Version was {}".format(sourceFont.version)) if self.sourceFont.version != None: self.sourceFont.version += ";" + projectName + " " + version else: 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) # print("Version now is {}".format(sourceFont.version)) @@ -523,30 +554,30 @@ class font_patcher: # Define the character ranges # Symbol font ranges self.patch_set = [ - {'Enabled': True, 'Name': "Seti-UI + Custom", 'Filename': "original-source.otf", 'Exact': False, 'SymStart': 0xE4FA, 'SymEnd': 0xE531, 'SrcStart': 0xE5FA, 'SrcEnd': 0xE631, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': True, 'Name': "Devicons", 'Filename': "devicons.ttf", 'Exact': False, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'SrcEnd': 0xE7C5, 'ScaleGlyph': DEVI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, - {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, - {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, - {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, - {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CA, 'SymEnd': 0xE0CA, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, - {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, - {'Enabled': self.args.pomicons, 'Name': "Pomicons", 'Filename': "Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.fontawesome, 'Name': "Font Awesome", 'Filename': "FontAwesome.otf", 'Exact': True, 'SymStart': 0xF000, 'SymEnd': 0xF2E0, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': FONTA_SCALE_LIST, 'Attributes': SYM_ATTR_FONTA}, - {'Enabled': self.args.fontawesomeextension, 'Name': "Font Awesome Extension", 'Filename': "font-awesome-extension.ttf", 'Exact': False, 'SymStart': 0xE000, 'SymEnd': 0xE0A9, 'SrcStart': 0xE200, 'SrcEnd': 0xE2A9, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, # Maximize - {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x23FB, 'SymEnd': 0x23FE, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': 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, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, # Heavy Circle (aka Power Off) - {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'SrcEnd': 0xFD46, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.weather, 'Name': "Weather Icons", 'Filename': "weathericons-regular-webfont.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF0EB, 'SrcStart': 0xE300, 'SrcEnd': 0xE3EB, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.fontlinux, 'Name': "Font Logos (Font Linux)", 'Filename': "font-logos.ttf", 'Exact': self.fontlinuxExactEncodingPosition, 'SymStart': 0xF100, 'SymEnd': 0xF12D, 'SrcStart': 0xF300, 'SrcEnd': 0xF32D, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'SrcEnd': 0xF505, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0xF27C, 'SymEnd': 0xF27C, 'SrcStart': 0xF4A9, 'SrcEnd': 0xF4A9, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Desktop - {'Enabled': self.args.custom, 'Name': "Custom", 'Filename': self.args.custom, 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': 0x0000, 'SrcEnd': 0x0000, 'ScaleGlyph': None, 'Attributes': CUSTOM_ATTR} + {'Enabled': True, 'Name': "Seti-UI + Custom", 'Filename': "original-source.otf", 'Exact': False, 'SymStart': 0xE4FA, 'SymEnd': 0xE531, 'SrcStart': 0xE5FA, 'SrcEnd': 0xE631, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': True, 'Name': "Devicons", 'Filename': "devicons.ttf", 'Exact': False, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'SrcEnd': 0xE7C5, 'ScaleGlyph': DEVI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CA, 'SymEnd': 0xE0CA, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.pomicons, 'Name': "Pomicons", 'Filename': "Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.fontawesome, 'Name': "Font Awesome", 'Filename': "font-awesome/FontAwesome.otf", 'Exact': True, 'SymStart': 0xF000, 'SymEnd': 0xF2E0, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': FONTA_SCALE_LIST, 'Attributes': SYM_ATTR_FONTA}, + {'Enabled': self.args.fontawesomeextension, 'Name': "Font Awesome Extension", 'Filename': "font-awesome-extension.ttf", 'Exact': False, 'SymStart': 0xE000, 'SymEnd': 0xE0A9, 'SrcStart': 0xE200, 'SrcEnd': 0xE2A9, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, # Maximize + {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x23FB, 'SymEnd': 0x23FE, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': 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, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, # Heavy Circle (aka Power Off) + {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'SrcEnd': 0xFD46, 'ScaleGlyph': None, '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, 'SrcEnd': 0xE3EB, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.fontlinux, 'Name': "Font Logos (Font Linux)", 'Filename': "font-logos.ttf", 'Exact': self.fontlinuxExactEncodingPosition, 'SymStart': 0xF100, 'SymEnd': 0xF12D, 'SrcStart': 0xF300, 'SrcEnd': 0xF32D, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'SrcEnd': 0xF505, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': self.octiconsExactEncodingPosition, 'SymStart': 0xF27C, 'SymEnd': 0xF27C, 'SrcStart': 0xF4A9, 'SrcEnd': 0xF4A9, 'ScaleGlyph': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Desktop + {'Enabled': self.args.codicons, 'Name': "Codicons", 'Filename': "codicons/codicon.ttf", 'Exact': True, 'SymStart': 0xEA60, 'SymEnd': 0xEBEB, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.custom, 'Name': "Custom", 'Filename': self.args.custom, 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': 0x0000, 'SrcEnd': 0x0000, 'ScaleGlyph': None, 'Attributes': CUSTOM_ATTR} ] - def setup_line_dimensions(self): # win_ascent and win_descent are used to set the line height for windows fonts. # hhead_ascent and hhead_descent are used to set the line height for mac fonts. @@ -558,6 +589,9 @@ class font_patcher: self.sourceFont.os2_winascent += 1 # Make the line size identical for windows and mac + # ! This is broken because hhea* is changed but os2_typo* is not + # ! On the other hand we need intact (i.e. original) typo values + # ! in get_sourcefont_dimensions() @TODO FIXME self.sourceFont.hhea_ascent = self.sourceFont.os2_winascent self.sourceFont.hhea_descent = -self.sourceFont.os2_windescent @@ -577,6 +611,9 @@ class font_patcher: 'width' : 0, 'height': 0, } + if self.sourceFont.os2_use_typo_metrics: + self.font_dim['ymin'] = self.sourceFont.os2_typodescent + self.font_dim['ymax'] = self.sourceFont.os2_typoascent # Find the biggest char width # Ignore the y-values, os2_winXXXXX values set above are used for line height @@ -622,10 +659,8 @@ class font_patcher: careful = True if exactEncoding is False: - sourceFontList = [] + sourceFontList = list(range(sourceFontStart, sourceFontEnd + 1)) sourceFontCounter = 0 - for i in range(sourceFontStart, sourceFontEnd + 1): - sourceFontList.append(format(i, 'X')) scale_factor = 0 if scaleGlyph: @@ -638,21 +673,18 @@ class font_patcher: # and only copy those that are not already contained in the source font if symbolFontStart == 0: symbolFont.selection.all() - self.sourceFont.selection.all() careful = True else: symbolFont.selection.select((str("ranges"), str("unicode")), symbolFontStart, symbolFontEnd) - self.sourceFont.selection.select((str("ranges"), str("unicode")), sourceFontStart, sourceFontEnd) - # Get number of selected non-empty glyphs @TODO FIXME - for index, sym_glyph in enumerate(symbolFont.selection.byGlyphs): - glyphSetLength += 1 - # end for + # Get number of selected non-empty glyphs + symbolFontSelection = list(symbolFont.selection.byGlyphs) + glyphSetLength = len(symbolFontSelection) if self.args.quiet is False: sys.stdout.write("Adding " + str(max(1, glyphSetLength)) + " Glyphs from " + setName + " Set \n") - for index, sym_glyph in enumerate(symbolFont.selection.byGlyphs): + for index, sym_glyph in enumerate(symbolFontSelection): index = max(1, index) try: @@ -663,25 +695,16 @@ class font_patcher: if exactEncoding: # use the exact same hex values for the source font as for the symbol font currentSourceFontGlyph = sym_glyph.encoding - - # Save as a hex string without the '0x' prefix - copiedToSlot = format(sym_glyph.unicode, 'X') else: # use source font defined hex values based on passed in start and end - # convince that this string really is a hex: - currentSourceFontGlyph = int("0x" + sourceFontList[sourceFontCounter], 16) - copiedToSlot = sourceFontList[sourceFontCounter] + currentSourceFontGlyph = sourceFontList[sourceFontCounter] sourceFontCounter += 1 - if int(copiedToSlot, 16) < 0: - print("Found invalid glyph slot number. Skipping.") - continue - if self.args.quiet is False: if self.args.progressbars: update_progress(round(float(index + 1) / glyphSetLength, 2)) else: - progressText = "\nUpdating glyph: " + str(sym_glyph) + " " + str(sym_glyph.glyphname) + " putting at: " + copiedToSlot + progressText = "\nUpdating glyph: {} {} putting at: {:X}".format(sym_glyph, sym_glyph.glyphname, currentSourceFontGlyph) sys.stdout.write(progressText) sys.stdout.flush() @@ -690,15 +713,16 @@ class font_patcher: # check if a glyph already exists in this location if careful or 'careful' in sym_attr['params']: - if copiedToSlot.startswith("uni"): - copiedToSlot = copiedToSlot[3:] - codepoint = int("0x" + copiedToSlot, 16) - if codepoint in self.sourceFont: + if currentSourceFontGlyph in self.sourceFont: if self.args.quiet is False: - print(" Found existing Glyph at {}. Skipping...".format(copiedToSlot)) - + print(" Found existing Glyph at {:X}. Skipping...".format(currentSourceFontGlyph)) # We don't want to touch anything so move to next Glyph continue + else: + # If we overwrite an existing glyph all subtable entries regarding it will be wrong + # (Probably; at least if we add a symbol and do not substitude a ligature or such) + if currentSourceFontGlyph in self.sourceFont: + self.sourceFont[currentSourceFontGlyph].removePosSub("*") # Select and copy symbol from its encoding point # We need to do this select after the careful check, this way we don't @@ -750,7 +774,7 @@ class font_patcher: if 'overlap' in sym_attr['params']: scale_ratio_x *= 1 + sym_attr['params']['overlap'] scale_ratio_y *= 1 + sym_attr['params']['overlap'] - self.sourceFont.transform(psMat.scale(scale_ratio_x, scale_ratio_y)) + self.sourceFont[currentSourceFontGlyph].transform(psMat.scale(scale_ratio_x, scale_ratio_y)) # Use the dimensions from the newly pasted and stretched glyph sym_dim = get_glyph_dimensions(self.sourceFont[currentSourceFontGlyph]) @@ -781,7 +805,7 @@ class font_patcher: x_align_distance += overlap_width align_matrix = psMat.translate(x_align_distance, y_align_distance) - self.sourceFont.transform(align_matrix) + self.sourceFont[currentSourceFontGlyph].transform(align_matrix) # Needed for setting 'advance width' on each glyph so they do not overlap, # also ensures the font is considered monospaced on Windows by setting the @@ -793,12 +817,6 @@ class font_patcher: # does not overlap the bearings (edges) self.remove_glyph_neg_bearings(self.sourceFont[currentSourceFontGlyph]) - # reset selection so iteration works properly @TODO fix? rookie misunderstanding? - # This is likely needed because the selection was changed when the glyph was copy/pasted - if symbolFontStart == 0: - symbolFont.selection.all() - else: - symbolFont.selection.select((str("ranges"), str("unicode")), symbolFontStart, symbolFontEnd) # end for if self.args.quiet is False or self.args.progressbars: diff --git a/original/.gitignore b/original/.gitignore new file mode 100644 index 0000000..f7ad452 --- /dev/null +++ b/original/.gitignore @@ -0,0 +1,3 @@ +*.ttf +*.ttx +*.zip diff --git a/patch_Iosevka.sh b/patch_Iosevka.sh new file mode 100755 index 0000000..01840d1 --- /dev/null +++ b/patch_Iosevka.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# usage: patch.sh [version of Iosevka] + +if [[ -z "$1" ]]; then + echo "Need an Iosevka version. + Example: patch.sh 11.2.4" + exit 1 +fi + +if ! command -v fontforge >/dev/null; then + printf "\033[1;31mfontforge\033[0m is not installed.\n" + exit 1 +fi + +if ! command -v ttx >/dev/null; then + printf "\033[1;31mfonttools\033[0m is not installed.\n" + exit 1 +fi + +version="$1" +variants=( + "bold" + "italic" + "bolditalic" + "regular" +) + +# Get the zip files from Github +echo "Downloading Iosevka Term version ${version} zip file ..." +curl -fsSL https://github.com/be5invis/Iosevka/releases/download/v${version}/ttf-iosevka-term-${version}.zip -o ./original/iosevka-term.zip + +echo "Unzipping the downloaded archive ..." +unzip ./original/iosevka-term.zip -d ./original + +for variant in "${variants[@]}"; do + echo "Patching Iosevka term ${variant} ..." + + # Run the font-patcher script + fontforge -script ./font-patcher --quiet --no-progressbars --careful --complete ./original/iosevka-term-${variant}.ttf + mv ./*Complete.ttf ./patched/iosevka-term-${variant}-nerd-font.ttf + + # Correct xAvgCharWidth + ttx -t "OS/2" ./original/iosevka-term-${variant}.ttf + ttx -t "OS/2" ./patched/iosevka-term-${variant}-nerd-font.ttf + original_x_avg_char_width=$(grep xAvgCharWidth ./original/iosevka-term-${variant}.ttx | cut -d '"' -f 2) + sed -i "s/xAvgCharWidth value=\"[0-9]\+\"/xAvgCharWidth value=\"${original_x_avg_char_width}\"/g" ./patched/iosevka-term-${variant}-nerd-font.ttx + mv ./patched/iosevka-term-${variant}-nerd-font.ttf ./patched/iosevka-term-${variant}-nerd-font.original.ttf + ttx -o ./patched/iosevka-term-${variant}-nerd-font.ttf -m ./patched/iosevka-term-${variant}-nerd-font.original.ttf ./patched/iosevka-term-${variant}-nerd-font.ttx + + # Optionally build hdmx table and correct TTF font family name (for Sarasa) + #python3 ./build-hdmx-for-sarasa.py ./patched/iosevka-term-${variant}-nerd-font.ttf + #python3 ./correct-ttf-font-family-name.py ./patched/iosevka-term-${variant}-nerd-font.ttf +done diff --git a/patched/.gitignore b/patched/.gitignore new file mode 100644 index 0000000..ba6e845 --- /dev/null +++ b/patched/.gitignore @@ -0,0 +1,2 @@ +*.ttf +*.ttx diff --git a/src/glyphs/NerdFontsSymbols 1000 EM Nerd Font Complete Blank.sfd b/src/glyphs/NerdFontsSymbols 1000 EM Nerd Font Complete Blank.sfd new file mode 100644 index 0000000..d49553e --- /dev/null +++ b/src/glyphs/NerdFontsSymbols 1000 EM Nerd Font Complete Blank.sfd @@ -0,0 +1,59 @@ +SplineFontDB: 3.0 +FontName: Symbols-1000-em +FullName: Symbols-1000-em +FamilyName: Symbols +Weight: Regular +Copyright: Copyright (c) 2016, Ryan McIntyre +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -100 +UnderlineWidth: 50 +Ascent: 800 +Descent: 200 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 913 -638292798 6571593] +FSType: 0 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1480466430 +ModificationTime: 1480467813 +PfmFamily: 17 +TTFWeight: 400 +TTFWidth: 5 +LineGap: 90 +VLineGap: 0 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 90 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +LangName: 1033 +Encoding: UnicodeFull +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -72 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 64 8 8 +OnlyBitmaps: 1 +BeginPrivate: 0 +EndPrivate +TeXData: 1 0 0 346030 173015 115343 0 1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144 +BeginChars: 1114112 0 +EndChars +EndSplineFont diff --git a/src/glyphs/NerdFontsSymbols 2048 EM Nerd Font Complete Blank.sfd b/src/glyphs/NerdFontsSymbols 2048 EM Nerd Font Complete Blank.sfd new file mode 100644 index 0000000..4c0601b --- /dev/null +++ b/src/glyphs/NerdFontsSymbols 2048 EM Nerd Font Complete Blank.sfd @@ -0,0 +1,59 @@ +SplineFontDB: 3.0 +FontName: Symbols-2048-em +FullName: Symbols-2048-em +FamilyName: Symbols +Weight: Regular +Copyright: Copyright (c) 2016, Ryan McIntyre +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -204 +UnderlineWidth: 102 +Ascent: 1638 +Descent: 410 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 913 -638292798 6571593] +FSType: 0 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1480466430 +ModificationTime: 1480467841 +PfmFamily: 17 +TTFWeight: 400 +TTFWidth: 5 +LineGap: 184 +VLineGap: 0 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 184 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +LangName: 1033 +Encoding: UnicodeFull +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -72 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 64 8 8 +OnlyBitmaps: 1 +BeginPrivate: 0 +EndPrivate +TeXData: 1 0 0 346030 173015 115343 0 1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144 +BeginChars: 1114112 0 +EndChars +EndSplineFont diff --git a/src/glyphs/Symbols-1000-em Nerd Font Complete.ttf b/src/glyphs/Symbols-1000-em Nerd Font Complete.ttf new file mode 100644 index 0000000..713c242 Binary files /dev/null and b/src/glyphs/Symbols-1000-em Nerd Font Complete.ttf differ diff --git a/src/glyphs/Symbols-2048-em Nerd Font Complete.ttf b/src/glyphs/Symbols-2048-em Nerd Font Complete.ttf new file mode 100644 index 0000000..60db517 Binary files /dev/null and b/src/glyphs/Symbols-2048-em Nerd Font Complete.ttf differ diff --git a/src/glyphs/codicons/codicon.ttf b/src/glyphs/codicons/codicon.ttf new file mode 100644 index 0000000..ae1034e Binary files /dev/null and b/src/glyphs/codicons/codicon.ttf differ diff --git a/src/glyphs/FontAwesome.otf b/src/glyphs/font-awesome/FontAwesome.otf similarity index 100% rename from src/glyphs/FontAwesome.otf rename to src/glyphs/font-awesome/FontAwesome.otf diff --git a/src/glyphs/PowerlineSymbols.otf b/src/glyphs/powerline-symbols/PowerlineSymbols.otf similarity index 100% rename from src/glyphs/PowerlineSymbols.otf rename to src/glyphs/powerline-symbols/PowerlineSymbols.otf diff --git a/src/glyphs/weathericons-regular-webfont.ttf b/src/glyphs/weather-icons/weathericons-regular-webfont.ttf similarity index 100% rename from src/glyphs/weathericons-regular-webfont.ttf rename to src/glyphs/weather-icons/weathericons-regular-webfont.ttf diff --git a/update.sh b/update.sh index 1b70c9e..c6bc37b 100755 --- a/update.sh +++ b/update.sh @@ -1,47 +1,40 @@ -#!/bin/sh - -# MIT License - -# Copyright (c) 2021 FollieHiyuki - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. +#!/usr/bin/env bash echo "Downloading 'font-patcher' script..." -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/font-patcher -o ./font-patcher +curl -fsSL https://github.com/ryanoasis/nerd-fonts/raw/master/font-patcher -o ./font-patcher chmod 755 ./font-patcher -echo " -Creating directory src/glyphs..." -mkdir -p ./src/glyphs +for path in codicons font-awesome powerline-symbols weather-icons; do + mkdir -p ./src/glyphs/"$path" +done -echo " -Downloading glyph fonts..." -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/FontAwesome.otf -o ./src/glyphs/FontAwesome.otf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/Pomicons.otf -o ./src/glyphs/Pomicons.otf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/PowerlineExtraSymbols.otf -o ./src/glyphs/PowerlineExtraSymbols.otf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/PowerlineSymbols.otf -o ./src/glyphs/PowerlineSymbols.otf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/Unicode_IEC_symbol_font.otf -o ./src/glyphs/Unicode_IEC_symbol_font.otf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/devicons.ttf -o ./src/glyphs/devicons.ttf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/font-awesome-extension.ttf -o ./src/glyphs/font-awesome-extension.ttf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/font-logos.ttf -o ./src/glyphs/font-logos.ttf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/materialdesignicons-webfont.ttf -o ./src/glyphs/materialdesignicons-webfont.ttf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/octicons.ttf -o ./src/glyphs/octicons.ttf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/original-source.otf -o ./src/glyphs/original-source.otf -curl -fL https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs/weathericons-regular-webfont.ttf -o ./src/glyphs/weathericons-regular-webfont.ttf -chmod 644 ./src/glyphs/* +echo "Downloading glyph fonts..." +glyphs=( + "codicons/codicon.ttf" + "font-awesome/FontAwesome.otf" + "powerline-symbols/PowerlineSymbols.otf" + "weather-icons/weathericons-regular-webfont.ttf" + "NerdFontsSymbols 1000 EM Nerd Font Complete Blank.sfd" + "NerdFontsSymbols 2048 EM Nerd Font Complete Blank.sfd" + "Pomicons.otf" + "PowerlineExtraSymbols.otf" + "Symbols-1000-em Nerd Font Complete.ttf" + "Symbols-2048-em Nerd Font Complete.ttf" + "Unicode_IEC_symbol_font.otf" + "devicons.ttf" + "font-awesome-extension.ttf" + "font-logos.ttf" + "materialdesignicons-webfont.ttf" + "octicons.ttf" + "original-source.otf" +) + +upstream_src_glyphs_url="https://github.com/ryanoasis/nerd-fonts/raw/master/src/glyphs" + +for glyph in "${glyphs[@]}"; do + # replace all `whitespace` characters with `%20` + percent_encoded_uri="${upstream_src_glyphs_url}/${glyph//\ /%20}" + + curl -fsSL ${percent_encoded_uri} -o "src/glyphs/${glyph}" +done +find ./src/glyphs/ -type f -exec chmod 644 '{}' \;