├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── LICENSE ├── README.md ├── TableHEADWriter.py ├── delugia_book.png ├── delugia_powerline.png ├── do_generate ├── extract-extra-glyphs └── rename-font /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v*' 9 | pull_request: 10 | branches: 11 | - master 12 | # schedule: 13 | # - cron: "0 13 * * *" 14 | 15 | jobs: 16 | check-for-new-cascadia: 17 | runs-on: ubuntu-22.04 18 | outputs: 19 | tag_name: ${{ env.CASCADIATAG }} 20 | tag_exists: ${{ steps.check_tag.outputs.exists }} 21 | 22 | steps: 23 | - name: Fetch latest release of Cascadia Code 24 | uses: octokit/request-action@v2.x 25 | id: get_latest_release 26 | with: 27 | route: GET /repos/microsoft/cascadia-code/releases/latest 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | - name: Get the latest Cascadia tag 31 | run: | 32 | echo "CASCADIATAG=${{ fromJson(steps.get_latest_release.outputs.data).tag_name }}" >> $GITHUB_ENV 33 | - name: Check if tag exists 34 | uses: mukunku/tag-exists-action@v1.6.0 35 | id: check_tag 36 | with: 37 | tag: ${{ env.CASCADIATAG }} 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | - name: Summary 41 | run: | 42 | echo "Latest Cascadia tag is $CASCADIATAG" 43 | 44 | build-and-release: 45 | needs: check-for-new-cascadia 46 | if: ${{ github.event_name != 'schedule' || needs.check-for-new-cascadia.outputs.tag_exists != 'true' }} 47 | runs-on: ubuntu-22.04 48 | env: 49 | CASCADIATAG: ${{ needs.check-for-new-cascadia.outputs.tag_name }} 50 | CASCADIATAG_ISNOTNEW: ${{ needs.check-for-new-cascadia.outputs.tag_exists }} 51 | 52 | steps: 53 | - uses: actions/checkout@v4 54 | with: 55 | fetch-depth: 0 56 | - name: Decide on version 57 | run: | 58 | if [ "${CASCADIATAG_ISNOTNEW}" = "false" ]; then 59 | echo New release is not tagged yet in our repo 60 | echo It will only be tagged after successfull release in job 'Create tag' 61 | OURVERSION=${CASCADIATAG} 62 | else 63 | echo Re-release uses our manual tags and/or patchlevel 64 | OURVERSION=`git describe --always --tags` 65 | fi 66 | echo "OURVERSION=${OURVERSION}" >> $GITHUB_ENV 67 | - name: Download latest version of Cascadia 68 | uses: robinraju/release-downloader@v1.10 69 | with: 70 | repository: "microsoft/cascadia-code" 71 | tag: ${{ needs.check-for-new-cascadia.outputs.tag_name }} 72 | fileName: "*.zip" 73 | - name: Open Cascadia release 74 | run: | 75 | unzip CascadiaCode*.zip 'ttf/*' 76 | 77 | # Ubuntu 20.04 has only fontforge release 2020, but there are some vital bugfixes in the 2022 release 78 | # This can be replaced with the ordinary apt package when Ubuntu updates, probably with 22.10? 79 | # On the other hand ... why not be on the latest release always? 80 | - name: Fetch FontForge 81 | run: | 82 | sudo apt install software-properties-common python3-fontforge fuse -y -q 83 | curl -L "https://github.com/fontforge/fontforge/releases/download/20230101/FontForge-2023-01-01-a1dad3e-x86_64.AppImage" \ 84 | --output fontforge 85 | chmod u+x fontforge 86 | echo Try appimage 87 | ./fontforge --version 88 | export PATH=`pwd`:$PATH 89 | echo "PATH=$PATH" >> $GITHUB_ENV 90 | echo Try appimage with path 91 | fontforge --version 92 | 93 | - name: Get Font Patcher 94 | uses: robinraju/release-downloader@v1.10 95 | with: 96 | repository: "ryanoasis/nerd-fonts" 97 | latest: true 98 | fileName: "FontPatcher.zip" 99 | - name: Open Font Patcher release 100 | run: | 101 | unzip FontPatcher.zip 102 | 103 | - name: Install PIP 104 | run: sudo apt install python3-pip -y 105 | - name: Install configparser 106 | run: pip3 install configparser 107 | - name: Extract additional powerline glyphs 108 | run: fontforge -lang=ff -script "`pwd`/extract-extra-glyphs" "`pwd`" `pwd`/src/glyphs/octicons/octicons.ttf 109 | - name: Build Powerline 110 | run: | 111 | ./do_generate 01 --powerline --mono CascadiaCodePL-Regular.ttf DelugiaPL.ttf "Delugia PL" 112 | ./do_generate 02 --powerline --mono CascadiaCodePL-Bold.ttf DelugiaPL-Bold.ttf "Delugia PL" 113 | ./do_generate 03 --powerline --mono CascadiaCodePL-Italic.ttf DelugiaPL-Italic.ttf "Delugia PL" 114 | ./do_generate 04 --powerline --mono CascadiaCodePL-BoldItalic.ttf DelugiaPL-BoldItalic.ttf "Delugia PL" 115 | ./do_generate 05 --powerline --mono CascadiaCodePL-Light.ttf DelugiaPLLight.ttf "Delugia PL" 116 | ./do_generate 06 --powerline --mono CascadiaCodePL-LightItalic.ttf DelugiaPLLight-Italic.ttf "Delugia PL" 117 | mkdir delugia-powerline 118 | mv Delugia*ttf delugia-powerline 119 | zip delugia-powerline.zip delugia-powerline/* 120 | - name: Build MonoPowerline 121 | run: | 122 | ./do_generate 11 --powerline --mono CascadiaMonoPL-Regular.ttf DelugiaMonoPL.ttf "Delugia PL Mono" 123 | ./do_generate 12 --powerline --mono CascadiaMonoPL-Bold.ttf DelugiaMonoPL-Bold.ttf "Delugia PL Mono" 124 | ./do_generate 13 --powerline --mono CascadiaMonoPL-Italic.ttf DelugiaMonoPL-Italic.ttf "Delugia PL Mono" 125 | ./do_generate 14 --powerline --mono CascadiaMonoPL-BoldItalic.ttf DelugiaMonoPL-BoldItalic.ttf "Delugia PL Mono" 126 | ./do_generate 15 --powerline --mono CascadiaMonoPL-Light.ttf DelugiaMonoPLLight.ttf "Delugia PL Mono" 127 | ./do_generate 16 --powerline --mono CascadiaMonoPL-LightItalic.ttf DelugiaMonoPLLight-Italic.ttf "Delugia PL Mono" 128 | mkdir delugia-mono-powerline 129 | mv Delugia*ttf delugia-mono-powerline 130 | zip delugia-mono-powerline.zip delugia-mono-powerline/* 131 | - name: Build Complete 132 | run: | 133 | ./do_generate 21 -c --mono CascadiaCodePL-Regular.ttf DelugiaComplete.ttf "Delugia" 134 | ./do_generate 22 -c --mono CascadiaCodePL-Bold.ttf DelugiaComplete-Bold.ttf "Delugia" 135 | ./do_generate 23 -c --mono CascadiaCodePL-Italic.ttf DelugiaComplete-Italic.ttf "Delugia" 136 | ./do_generate 24 -c --mono CascadiaCodePL-BoldItalic.ttf DelugiaComplete-BoldItalic.ttf "Delugia" 137 | ./do_generate 25 -c --mono CascadiaCodePL-Light.ttf DelugiaCompleteLight.ttf "Delugia" 138 | ./do_generate 26 -c --mono CascadiaCodePL-LightItalic.ttf DelugiaCompleteLight-Italic.ttf "Delugia" 139 | mkdir delugia-complete 140 | mv Delugia*ttf delugia-complete 141 | zip delugia-complete.zip delugia-complete/* 142 | - name: Build Mono Complete 143 | run: | 144 | ./do_generate 31 -c --mono CascadiaMonoPL-Regular.ttf DelugiaMonoComplete.ttf "Delugia Mono" 145 | ./do_generate 32 -c --mono CascadiaMonoPL-Bold.ttf DelugiaMonoComplete-Bold.ttf "Delugia Mono" 146 | ./do_generate 33 -c --mono CascadiaMonoPL-Italic.ttf DelugiaMonoComplete-Italic.ttf "Delugia Mono" 147 | ./do_generate 34 -c --mono CascadiaMonoPL-BoldItalic.ttf DelugiaMonoComplete-BoldItalic.ttf "Delugia Mono" 148 | ./do_generate 35 -c --mono CascadiaMonoPL-Light.ttf DelugiaMonoCompleteLight.ttf "Delugia Mono" 149 | ./do_generate 36 -c --mono CascadiaMonoPL-LightItalic.ttf DelugiaMonoCompleteLight-Italic.ttf "Delugia Mono" 150 | mkdir delugia-mono-complete 151 | mv Delugia*ttf delugia-mono-complete 152 | zip delugia-mono-complete.zip delugia-mono-complete/* 153 | - name: Build Book Complete 154 | run: | 155 | ./do_generate 41 -c -c CascadiaCodePL-Regular.ttf DelugiaBook.ttf "Delugia Book" 156 | ./do_generate 42 -c -c CascadiaCodePL-Bold.ttf DelugiaBook-Bold.ttf "Delugia Book" 157 | ./do_generate 43 -c -c CascadiaCodePL-Italic.ttf DelugiaBook-Italic.ttf "Delugia Book" 158 | ./do_generate 44 -c -c CascadiaCodePL-BoldItalic.ttf DelugiaBook-BoldItalic.ttf "Delugia Book" 159 | ./do_generate 45 -c -c CascadiaCodePL-Light.ttf DelugiaBookLight.ttf "Delugia Book" 160 | ./do_generate 46 -c -c CascadiaCodePL-LightItalic.ttf DelugiaBookLight-Italic.ttf "Delugia Book" 161 | mkdir delugia-book 162 | mv Delugia*ttf delugia-book 163 | zip delugia-book.zip delugia-book/* 164 | - name: Check for preexisting glyphs 165 | run: | 166 | grep 'Skipping...' process*.log | grep -vE ' Powerline(Extra)?Symbols>' 167 | - uses: actions/upload-artifact@v4 168 | with: 169 | name: Delugia Powerline 170 | path: "delugia-powerline" 171 | - uses: actions/upload-artifact@v4 172 | with: 173 | name: Delugia Mono Powerline 174 | path: "delugia-mono-powerline" 175 | - uses: actions/upload-artifact@v4 176 | with: 177 | name: Delugia Complete 178 | path: "delugia-complete" 179 | - uses: actions/upload-artifact@v4 180 | with: 181 | name: Delugia Mono Complete 182 | path: "delugia-mono-complete" 183 | - uses: actions/upload-artifact@v4 184 | with: 185 | name: Delugia Book 186 | path: "delugia-book" 187 | 188 | # Release part 189 | - name: Create tag 190 | if: ${{ github.event_name != 'pull_request' && !startsWith(github.ref, 'refs/tags/') && needs.check-for-new-cascadia.outputs.tag_exists != 'true' }} 191 | uses: EndBug/latest-tag@latest 192 | with: 193 | ref: ${{ needs.check-for-new-cascadia.outputs.tag_name }} 194 | description: "Bump Delugia version to ${{ needs.check-for-new-cascadia.outputs.tag_name }}" 195 | - name: Get tag name 196 | id: get_tag_name 197 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 198 | uses: battila7/get-version-action@v2 199 | - name: Release 200 | uses: softprops/action-gh-release@v2 201 | if: ${{ github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/') || needs.check-for-new-cascadia.outputs.tag_exists != 'true') }} 202 | with: 203 | tag_name: ${{ startsWith(github.ref, 'refs/tags/') && steps.get_tag_name.outputs.version || needs.check-for-new-cascadia.outputs.tag_name }} 204 | files: | 205 | delugia-powerline.zip 206 | delugia-mono-powerline.zip 207 | delugia-complete.zip 208 | delugia-mono-complete.zip 209 | delugia-book.zip 210 | env: 211 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 212 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CascadiaCode*zip 2 | src/ 3 | otf/ 4 | ttf/ 5 | woff2/ 6 | __pycache__/* 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 Adam Cooper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![delugia image](/delugia_book.png) 2 | # Cascadia Code + Nerd Fonts 3 | Can we add Nerd Fonts to the [Cascadia Code](https://github.com/microsoft/cascadia-code) font using a GitHub Action? 4 | 5 | Inspired by [Scott Hanselman](https://www.hanselman.com/blog/PatchingTheNewCascadiaCodeToIncludePowerlineGlyphsAndOtherNerdFontsForTheWindowsTerminal.aspx) and [Alistair Young](https://github.com/microsoft/cascadia-code/issues/10?WT.mc_id=-blog-scottha#issuecomment-532969414). 6 | 7 | The answer, it turns out, is yes. 8 | 9 | I wrote a [blog post with more details](https://admcpr.com/automating-the-patching-of-cascadia-code-to-include-nerd-fonts) about how this works. 10 | 11 | [![Actions Status](https://github.com/adam7/delugia-code/workflows/Generate%20Fonts/badge.svg)](https://github.com/adam7/delugia-code/actions) 12 | 13 | > ⚠ Cascadia is now part of Nerd Fonts' [prepatched font repository](https://github.com/ryanoasis/nerd-fonts#patched-fonts). You can grab it there, and it is almost what you find as Delugia font here. There are some small differences, see below. 14 | 15 | ### What is Nerd Fonts anyway? 16 | [Nerd Fonts](https://www.nerdfonts.com) takes popular programming fonts and adds a bunch of Glyphs. They include all the absolutely [indispensable symbols](https://github.com/ryanoasis/nerd-fonts/wiki/Glyph-Sets-and-Code-Points) all nerds need in their favorite fonts. 17 | Go to their [repository](https://github.com/ryanoasis/nerd-fonts) or have a look at the [overview](https://www.nerdfonts.com/#cheat-sheet). 18 | 19 | Typically they come in two flavours: 20 | * Powerline (adds the symbols needed to have a basic [Powerline](https://github.com/powerline) and some more.) 21 | * Complete (adds even more Powerline symbols and all other symbols Nerd Fonts has collected.) 22 | 23 | _Powerline_ includes these symbols: 24 | * Powerline Symbols 25 | * [Seti-UI](https://atom.io/themes/seti-ui#current_icons) 26 | * [Devicons](http://vorillaz.github.io/devicons/) 27 | 28 | _Complete_ includes these symbols additionally: 29 | * [Powerline Extra Symbols](https://github.com/ryanoasis/powerline-extra-symbols) 30 | * [Pomicons](https://github.com/gabrielelana/pomicons) 31 | * [Font Awesome](https://github.com/FortAwesome/Font-Awesome) and [Extension](https://github.com/AndreLZGava/font-awesome-extension) 32 | * [Power Symbols](https://unicodepowersymbol.com/) 33 | * [Material Design Icons](https://github.com/Templarian/MaterialDesign) 34 | * [Font Logos](https://github.com/Lukas-W/font-logos) 35 | * [Octicons](https://github.com/github/octicons) 36 | 37 | ### Which font faces are available 38 | 39 | These three font versions are generated from Cascadia Code: 40 | * **Delugia Powerline** _Basic powerline glyphs, monospaced font_ 41 | * **Delugia Complete** _All Nerd Fonts glyphs, monospaced font_ 42 | * **Delugia Book** _All Nerd Fonts glyphs, proportional font (not recommended for coding/console)_ 43 | 44 | And the following two faces are generated from Cascadia Mono and don't have ligatures: 45 | * **Delugia Mono Powerline** _Basic powerline glyphs, monospaced font_ 46 | * **Delugia Mono Complete** _All Nerd Fonts glyphs, monospaced font_ 47 | 48 | All of these are available in light, regular, and bold weights. Complemented by matching italic fonts. 49 | 50 | ### How is Delugia special? 51 | Compared with other patched versions of Cascadia you will find 52 | * Added symbol ``⚡`` (0u26A1) used with some popular Powerline setups (for not 'Complete') 53 | 54 | ### How to use 55 | You can download the patched fonts from the [Releases page](https://github.com/adam7/delugia-code/releases) of this 56 | repo and install them as you would any other font. Once installed the font can be referenced as `Delugia *`. 57 | So if, for example, you want to use it in Windows Terminal you should add the lines 58 | 59 | ``` 60 | "font": 61 | { 62 | "face": "Delugia" 63 | } 64 | ``` 65 | 66 | to the corresponding profiles in your settings.json. 67 | 68 | ### Installation with [Chocolatey](https://chocolatey.org/install) 69 | You can install your preferred version, or versions, of Delugia using the standard Chocolatey incantations. 70 | 71 | * `choco install nerd-fonts-delugiamono-powerline` 72 | * `choco install nerd-fonts-delugiabook` 73 | * `choco install nerd-fonts-delugiapowerline` 74 | * `choco install nerd-fonts-delugiacomplete` 75 | * `choco install nerd-fonts-delugiamono-complete` 76 | 77 | ### Installation with [scoop.sh](https://scoop.sh) 78 | You can use [scoop.sh](https://scoop.sh) to install and update the font. At first install [scoop](https://github.com/lukesampson/scoop) and add extra bucket for [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts): 79 | 1) `iwr -useb get.scoop.sh | iex` 80 | 2) `scoop bucket add nerd-fonts` 81 | 3) `scoop install sudo` 82 | 4) One or more of 83 | * `sudo scoop install Delugia-Nerd-Font` 84 | * `sudo scoop install Delugia-Nerd-Font-Complete` 85 | * `sudo scoop install Delugia-Mono-Nerd-Font` 86 | * `sudo scoop install Delugia-Mono-Nerd-Font-Complete` 87 | * `sudo scoop install Delugia-Nerd-Font-Book` 88 | 89 | ### Example for Delugia on the command line 90 | 91 | ![Delugia Powerline](/delugia_powerline.png) 92 | 93 | ### Help! 94 | I know basically nothing about patching fonts so all contributions are 🦸‍ welcome. 95 | 96 | ### Note 97 | The naming changed a bit when we added the light and bold fonts. 98 | To reduce the font name length the 'Nerd Font' has been dropped out of the (file) names. 99 | The actual naming scheme changed to accommodate the new fonts and for your convenience we pack 100 | fonts that one particular user might want to use together in a zip archive. 101 | -------------------------------------------------------------------------------- /TableHEADWriter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf8 3 | # Nerd Fonts Version: 2.3.3 4 | 5 | import sys 6 | 7 | class TableHEADWriter: 8 | """ Access to the HEAD table without external dependencies """ 9 | def getlong(self, pos = None): 10 | """ Get four bytes from the font file as integer number """ 11 | if pos: 12 | self.goto(pos) 13 | return (ord(self.f.read(1)) << 24) + (ord(self.f.read(1)) << 16) + (ord(self.f.read(1)) << 8) + ord(self.f.read(1)) 14 | 15 | def getshort(self, pos = None): 16 | """ Get two bytes from the font file as integer number """ 17 | if pos: 18 | self.goto(pos) 19 | return (ord(self.f.read(1)) << 8) + ord(self.f.read(1)) 20 | 21 | def putlong(self, num, pos = None): 22 | """ Put number as four bytes into font file """ 23 | if pos: 24 | self.goto(pos) 25 | self.f.write(bytearray([(num >> 24) & 0xFF, (num >> 16) & 0xFF ,(num >> 8) & 0xFF, num & 0xFF])) 26 | self.modified = True 27 | 28 | def putshort(self, num, pos = None): 29 | """ Put number as two bytes into font file """ 30 | if pos: 31 | self.goto(pos) 32 | self.f.write(bytearray([(num >> 8) & 0xFF, num & 0xFF])) 33 | self.modified = True 34 | 35 | def calc_checksum(self, start, end, checksum = 0): 36 | """ Calculate a font table checksum, optionally ignoring another embedded checksum value (for table 'head') """ 37 | self.f.seek(start) 38 | for i in range(start, end - 4, 4): 39 | checksum += self.getlong() 40 | checksum &= 0xFFFFFFFF 41 | i += 4 42 | extra = 0 43 | for j in range(4): 44 | extra = extra << 8 45 | if i + j <= end: 46 | extra += ord(self.f.read(1)) 47 | checksum = (checksum + extra) & 0xFFFFFFFF 48 | return checksum 49 | 50 | def find_table(self, tablenames, idx): 51 | """ Search all tables for one of the tables in tablenames and store its metadata """ 52 | # Use font with index idx if this is a font collection file 53 | self.f.seek(0, 0) 54 | tag = self.f.read(4) 55 | if tag == b'ttcf': 56 | self.f.seek(2*2, 1) 57 | self.num_fonts = self.getlong() 58 | if (idx >= self.num_fonts): 59 | raise Exception('Trying to access subfont index {} but have only {} fonts'.format(idx, num_fonts)) 60 | for _ in range(idx + 1): 61 | offset = self.getlong() 62 | self.f.seek(offset, 0) 63 | elif idx != 0: 64 | raise Exception('Trying to access subfont but file is no collection') 65 | else: 66 | self.f.seek(0, 0) 67 | self.num_fonts = 1 68 | 69 | self.f.seek(4, 1) 70 | numtables = self.getshort() 71 | self.f.seek(3*2, 1) 72 | 73 | for i in range(numtables): 74 | tab_name = self.f.read(4) 75 | self.tab_check_offset = self.f.tell() 76 | self.tab_check = self.getlong() 77 | self.tab_offset = self.getlong() 78 | self.tab_length = self.getlong() 79 | if tab_name in tablenames: 80 | return True 81 | return False 82 | 83 | def find_head_table(self, idx): 84 | """ Search all tables for the HEAD table and store its metadata """ 85 | # Use font with index idx if this is a font collection file 86 | found = self.find_table([ b'head' ], idx) 87 | if not found: 88 | raise Exception('No HEAD table found in font idx {}'.format(idx)) 89 | 90 | 91 | def goto(self, where): 92 | """ Go to a named location in the file or to the specified index """ 93 | if type(where) is str: 94 | positions = {'checksumAdjustment': 2+2+4, 95 | 'flags': 2+2+4+4+4, 96 | 'lowestRecPPEM': 2+2+4+4+4+2+2+8+8+2+2+2+2+2, 97 | } 98 | where = self.tab_offset + positions[where] 99 | self.f.seek(where) 100 | 101 | 102 | def calc_full_checksum(self, check = False): 103 | """ Calculate the whole file's checksum """ 104 | self.f.seek(0, 2) 105 | self.end = self.f.tell() 106 | full_check = self.calc_checksum(0, self.end, (-self.checksum_adj) & 0xFFFFFFFF) 107 | if check and (0xB1B0AFBA - full_check) & 0xFFFFFFFF != self.checksum_adj: 108 | sys.exit("Checksum of whole font is bad") 109 | return full_check 110 | 111 | def calc_table_checksum(self, check = False): 112 | tab_check_new = self.calc_checksum(self.tab_offset, self.tab_offset + self.tab_length - 1, (-self.checksum_adj) & 0xFFFFFFFF) 113 | if check and tab_check_new != self.tab_check: 114 | sys.exit("Checksum of 'head' in font is bad") 115 | return tab_check_new 116 | 117 | def reset_table_checksum(self): 118 | new_check = self.calc_table_checksum() 119 | self.putlong(new_check, self.tab_check_offset) 120 | 121 | def reset_full_checksum(self): 122 | new_adj = (0xB1B0AFBA - self.calc_full_checksum()) & 0xFFFFFFFF 123 | self.putlong(new_adj, 'checksumAdjustment') 124 | 125 | def close(self): 126 | self.f.close() 127 | 128 | 129 | def __init__(self, filename): 130 | self.modified = False 131 | self.f = open(filename, 'r+b') 132 | 133 | self.find_head_table(0) 134 | 135 | self.flags = self.getshort('flags') 136 | self.lowppem = self.getshort('lowestRecPPEM') 137 | self.checksum_adj = self.getlong('checksumAdjustment') 138 | -------------------------------------------------------------------------------- /delugia_book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adam7/delugia-code/50a4fef1bf31ae3bc345608e58fac6b2d0f3cc84/delugia_book.png -------------------------------------------------------------------------------- /delugia_powerline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adam7/delugia-code/50a4fef1bf31ae3bc345608e58fac6b2d0f3cc84/delugia_powerline.png -------------------------------------------------------------------------------- /do_generate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # Create and rename one font style according to the specs 4 | # 5 | # Example invocation: 6 | # do_generate 01 --powerline --mono CascadiaCodePL-Regular.ttf DelugiaPowerline.ttf Delugia Regular 7 | # 8 | # No parameters are checked, but they are: 9 | # 1: Number of logfile 10 | # 2: Conversion spec #1 11 | # 3: Conversion spec #2 12 | # 4: Input font file name 13 | # 5: Output font file name 14 | # 6: Font family name 15 | 16 | set -e 17 | 18 | if [ "$#" -ne 6 ]; then 19 | exit 1 20 | fi 21 | 22 | PWD=$( pwd ) 23 | 24 | rm -f C*.ttf 25 | fontforge -script "${PWD}/font-patcher" --debug 2 --careful "${3}" --custom SomeExtraSymbols.sfd --no-progressbars "${PWD}/ttf/static/${4}" "${2}" --outputdir "${PWD}" | tee "process${1}.log" 26 | 27 | if [ -z "${OURVERSION}" ]; then 28 | # Github CI sets this variable, but this can be useful for manual calls: 29 | OURVERSION=`git describe --always --tags` 30 | fi 31 | fontforge -script "${PWD}/rename-font" --orig "${PWD}/ttf/static/${4}" --input ${PWD}/C*.ttf --output "${PWD}/${5}" --version "${OURVERSION}" --name "${6}" 32 | -------------------------------------------------------------------------------- /extract-extra-glyphs: -------------------------------------------------------------------------------- 1 | Open($2); 2 | SelectAll(); 3 | SelectFewer(0u26A1); 4 | Clear(); 5 | Save($1 + "/src/glyphs/SomeExtraSymbols.sfd"); 6 | -------------------------------------------------------------------------------- /rename-font: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf8 3 | 4 | import os.path 5 | import fontforge 6 | import sys, logging 7 | from argparse import ArgumentParser 8 | 9 | sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])) + '/bin/scripts/name_parser/') 10 | from FontnameParser import FontnameParser 11 | from TableHEADWriter import TableHEADWriter 12 | 13 | # Setup and parse the comand-line arguments 14 | parser = ArgumentParser() 15 | parser.add_argument("--input", help="input file name") 16 | parser.add_argument("--orig", help="original font filename") 17 | parser.add_argument("--output", help="output file name") 18 | parser.add_argument("--name", help="preferred family name") 19 | parser.add_argument("--version", help="text to add to the existing version") 20 | args = parser.parse_args() 21 | 22 | SIL_TABLE = [('cascadia ?(code|mono)( ?pl)?', args.name), ] 23 | 24 | print("\nRenaming process\n {}\n as {}\n -> {}".format(args.input, args.orig, args.output)) 25 | 26 | fname = os.path.splitext(os.path.basename(args.orig))[0] 27 | logger = logging.getLogger() 28 | n = FontnameParser(fname, logger) 29 | n.add_name_substitution_table(SIL_TABLE) 30 | n.set_keep_regular_in_family(False) 31 | if not n.parse_ok: 32 | sys.exit("Something with name parsing went wrong") 33 | 34 | # Open the file 35 | delugia=fontforge.open(args.input) 36 | 37 | # Rename the file 38 | n.rename_font(delugia) 39 | 40 | # Other information 41 | delugia.appendSFNTName("English (US)", "UniqueID", "{};{}".format(args.version, n.psname())) 42 | delugia.appendSFNTName("English (US)", "Trademark", "") 43 | 44 | # Mix our version information in 45 | delugia.sfntRevision = None # Auto-set (refreshed) by fontforge 46 | delugia.appendSFNTName("English (US)", "Version", args.version) 47 | delugia.version = args.version 48 | 49 | if n.psname().lower().find("mono"): 50 | # For MS-Windows console apps 51 | panose = list(delugia.os2_panose) 52 | if panose[0] < 3: # https://forum.high-logic.com/postedfiles/Panose.pdf 53 | panose[3] = 9 # 3 (4th value) = propotion: 9 = monospaced 54 | delugia.os2_panose = tuple(panose) 55 | 56 | # Save 57 | delugia.generate(args.output) 58 | print("Generated '{}' from {} version {}".format(args.output, n.fullname(), args.version)) 59 | 60 | # Fix fontforge destroying the font flags 61 | source_font = TableHEADWriter(args.orig) 62 | dest_font = TableHEADWriter(args.output) 63 | source_font.find_head_table(0) 64 | dest_font.find_head_table(0) 65 | 66 | print("Changing flags from 0x{:X} to 0x{:X}".format(dest_font.flags, source_font.flags)) 67 | dest_font.putshort(source_font.flags, 'flags') # clear 'ppem_to_int' etc 68 | print("Changing lowestRecPPEM from {} to {}".format(dest_font.lowppem, source_font.lowppem)) 69 | dest_font.putshort(source_font.lowppem, 'lowestRecPPEM') 70 | 71 | dest_font.reset_table_checksum() 72 | dest_font.reset_full_checksum() 73 | source_font.close() 74 | dest_font.close() 75 | --------------------------------------------------------------------------------