NotYAFC 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notyafc-1.0.0/PKG-INFO +256 -0
- notyafc-1.0.0/README.md +241 -0
- notyafc-1.0.0/pyproject.toml +73 -0
- notyafc-1.0.0/pyproject.toml.orig +64 -0
- notyafc-1.0.0/src/font_converter/__init__.py +4 -0
- notyafc-1.0.0/src/font_converter/__main__.py +45 -0
- notyafc-1.0.0/src/font_converter/assets/ico.png +0 -0
- notyafc-1.0.0/src/font_converter/assets/notyafc-1024.png +0 -0
- notyafc-1.0.0/src/font_converter/assets/notyafc.ico +0 -0
- notyafc-1.0.0/src/font_converter/assets/notyafc.svg +15 -0
- notyafc-1.0.0/src/font_converter/cli.py +543 -0
- notyafc-1.0.0/src/font_converter/constants.py +27 -0
- notyafc-1.0.0/src/font_converter/contours.py +336 -0
- notyafc-1.0.0/src/font_converter/css_kit.py +77 -0
- notyafc-1.0.0/src/font_converter/finder.py +213 -0
- notyafc-1.0.0/src/font_converter/font.py +530 -0
- notyafc-1.0.0/src/font_converter/gui/__init__.py +1 -0
- notyafc-1.0.0/src/font_converter/gui/conversion_dialog.py +110 -0
- notyafc-1.0.0/src/font_converter/gui/file_list.py +411 -0
- notyafc-1.0.0/src/font_converter/gui/instance_tree.py +583 -0
- notyafc-1.0.0/src/font_converter/gui/logs.py +51 -0
- notyafc-1.0.0/src/font_converter/gui/organization_dialog.py +417 -0
- notyafc-1.0.0/src/font_converter/gui/profile_options.py +316 -0
- notyafc-1.0.0/src/font_converter/gui/profiles.py +17 -0
- notyafc-1.0.0/src/font_converter/gui/scanner.py +42 -0
- notyafc-1.0.0/src/font_converter/gui/styles.py +658 -0
- notyafc-1.0.0/src/font_converter/gui/widgets.py +495 -0
- notyafc-1.0.0/src/font_converter/gui/window.py +1768 -0
- notyafc-1.0.0/src/font_converter/inspection.py +169 -0
- notyafc-1.0.0/src/font_converter/merge_curves.py +499 -0
- notyafc-1.0.0/src/font_converter/otf_builder.py +144 -0
- notyafc-1.0.0/src/font_converter/qu2cu.py +117 -0
- notyafc-1.0.0/src/font_converter/service.py +729 -0
- notyafc-1.0.0/src/font_converter/ttf_builder.py +107 -0
notyafc-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: NotYAFC
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Not Yet Another Font Converter: a free and open-source font converter for desktop and command-line use, written in Python.
|
|
5
|
+
Author: Cesare Gilento
|
|
6
|
+
Author-email: Cesare Gilento <ftCLI@proton.me>
|
|
7
|
+
Requires-Dist: cffsubr>=0.4.0
|
|
8
|
+
Requires-Dist: fonttools[pathops,woff]>=4.68.0
|
|
9
|
+
Requires-Dist: pathvalidate>=3.3.1
|
|
10
|
+
Requires-Dist: pyside6>=6.8
|
|
11
|
+
Requires-Dist: typer==0.28.0
|
|
12
|
+
Requires-Dist: ttfautohint-py>=0.6.1
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# NotYAFC — Not Yet Another Font Converter
|
|
17
|
+
> A free, open-source desktop app and CLI for batch font conversion. Local, controllable, and built on trusted tools.
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="https://raw.githubusercontent.com/ftCLI/NotYAFC/main/src/font_converter/assets/notyafc-1024.png" alt="NotYAFC logo" width="256" height="256">
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Tests%20%28ubuntu-latest%29&label=Tests%20%28Linux%29" alt="Tests (Linux)"></a>
|
|
25
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Tests%20%28windows-latest%29&label=Tests%20%28Windows%29" alt="Tests (Windows)"></a>
|
|
26
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Tests%20%28macos-latest%29&label=Tests%20%28macOS%29" alt="Tests (macOS)"></a>
|
|
27
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Lint%20and%20type%20check&label=Lint" alt="Lint"></a>
|
|
28
|
+
<a href="https://pypi.org/project/notyafc/"><img src="https://img.shields.io/pypi/v/notyafc?label=PyPI" alt="PyPI version"></a>
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
NotYAFC converts fonts between formats — TrueType, PostScript, WOFF, WOFF2 — and can extract fonts from collections or export variable-font instances as static files. It runs entirely on your machine, supports batch processing, and gives you fine-grained control over every conversion parameter.
|
|
34
|
+
|
|
35
|
+
It provides two interfaces:
|
|
36
|
+
|
|
37
|
+
- **GUI** — A PySide6 desktop application with drag-and-drop, progress tracking, and per-profile options.
|
|
38
|
+
- **CLI** — A Typer-based command-line tool for scripting and repeatable workflows.
|
|
39
|
+
|
|
40
|
+
Both interfaces share the same conversion engine, so you get identical results regardless of how you use NotYAFC.
|
|
41
|
+
|
|
42
|
+
## Why NotYAFC?
|
|
43
|
+
|
|
44
|
+
- **Local** — Your fonts never leave your machine. No uploads, no online services.
|
|
45
|
+
- **Batch-ready** — Add files or entire folders, scan recursively, and convert hundreds of fonts at once.
|
|
46
|
+
- **Transparent** — Built on [FontTools](https://github.com/fonttools/fonttools), `ttfautohint`, and `cffsubr`. No black-box conversion — just a practical interface around established font tools.
|
|
47
|
+
- **Fine-grained control** — Tune curve-conversion tolerance, target UPM, contour optimization, autohinting, subroutinization, and more.
|
|
48
|
+
- **Output, organized your way** — Build a custom folder structure from font properties and conversion settings, so even large batches land where you want them.
|
|
49
|
+
- **Batch-aware** — Pause, resume, or cancel mid-run. Incompatible fonts are explained, not silently skipped.
|
|
50
|
+
- **Dual interface** — Use the GUI for interactive work or the CLI for automation.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
### With uv (recommended)
|
|
55
|
+
|
|
56
|
+
```console
|
|
57
|
+
uv tool install notyafc
|
|
58
|
+
notyafc
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Try it without installing: `uvx notyafc`. Upgrade later with `uv tool upgrade notyafc`.
|
|
62
|
+
|
|
63
|
+
The CLI is available as `notyafc-cli`. Run `notyafc-cli --help` for available commands.
|
|
64
|
+
|
|
65
|
+
### From PyPI with pip
|
|
66
|
+
|
|
67
|
+
Install the latest release from [PyPI](https://pypi.org/project/notyafc/):
|
|
68
|
+
|
|
69
|
+
**Windows (PowerShell):**
|
|
70
|
+
```powershell
|
|
71
|
+
py -m venv .venv
|
|
72
|
+
.\.venv\Scripts\Activate.ps1
|
|
73
|
+
python -m pip install notyafc
|
|
74
|
+
notyafc
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**macOS and Linux:**
|
|
78
|
+
```console
|
|
79
|
+
python3 -m venv .venv
|
|
80
|
+
source .venv/bin/activate
|
|
81
|
+
python -m pip install notyafc
|
|
82
|
+
notyafc
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
To upgrade an existing installation, run `python -m pip install --upgrade notyafc`.
|
|
86
|
+
The command-line interface is available as `notyafc-cli`; run `notyafc-cli --help` for usage.
|
|
87
|
+
|
|
88
|
+
### From source
|
|
89
|
+
|
|
90
|
+
```console
|
|
91
|
+
git clone https://github.com/ftCLI/NotYAFC.git
|
|
92
|
+
cd NotYAFC
|
|
93
|
+
uv sync
|
|
94
|
+
uv run notyafc
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Conversion Profiles
|
|
98
|
+
|
|
99
|
+
| Profile | Description |
|
|
100
|
+
|---------|-------------|
|
|
101
|
+
| `ttf2otf` | TrueType → PostScript (TTF → OTF) |
|
|
102
|
+
| `otf2ttf` | PostScript → TrueType (OTF → TTF) |
|
|
103
|
+
| `ft2wf` | SFNT → WOFF / WOFF2 webfonts |
|
|
104
|
+
| `woff2ft` | WOFF → SFNT (TTF or OTF) |
|
|
105
|
+
| `woff22ft` | WOFF2 → SFNT (TTF or OTF) |
|
|
106
|
+
| `ttc2sfnt` | TTC/OTC collection → individual fonts |
|
|
107
|
+
| `var2static` | Variable font → static instances |
|
|
108
|
+
|
|
109
|
+
### Profile Options
|
|
110
|
+
|
|
111
|
+
#### TrueType → PostScript (`ttf2otf`)
|
|
112
|
+
|
|
113
|
+
- **Tolerance** (0.1–3, default 1) — Controls curve-conversion accuracy in thousandths of an em; the actual deviation scales with UPM. Lower values allow less deviation, but may increase point count and file size.
|
|
114
|
+
- **Target UPM** — Scale the font to a chosen units-per-em value.
|
|
115
|
+
- **Simplify contours** (0–3, default 0/off) — Experimental: merge neighboring smooth curves to reduce point count. Deviation is a multiple of Tolerance.
|
|
116
|
+
- **Subroutinize** (on by default) — Compress PostScript outlines using shared subroutines.
|
|
117
|
+
|
|
118
|
+
#### PostScript → TrueType (`otf2ttf`)
|
|
119
|
+
|
|
120
|
+
- **Tolerance** (0–3, default 1) — Controls curve-conversion accuracy in thousandths of an em; the actual deviation scales with UPM. Lower values allow less deviation, but may increase point count and file size.
|
|
121
|
+
- **Target UPM** — Scale the font to a chosen units-per-em value.
|
|
122
|
+
- **Autohint** (on by default) — Add TrueType hinting instructions via `ttfautohint`.
|
|
123
|
+
|
|
124
|
+
#### SFNT → WOFF / WOFF2 (`ft2wf`)
|
|
125
|
+
|
|
126
|
+
- **Format** — Choose WOFF, WOFF2, or both (both selected by default).
|
|
127
|
+
- **Obfuscate names** — Replace family, full, and PostScript names with hashes (including in the output filename).
|
|
128
|
+
- **Remove unused glyphs** — Drop glyphs not reachable from the character map or OpenType features.
|
|
129
|
+
- **Remove non-Windows names** — Strip `name` records for platforms other than Windows (platform ID 3).
|
|
130
|
+
- **Remove DSIG table** (WOFF only) — Remove the digital signature table.
|
|
131
|
+
- **Create CSS** — Write a `fonts.css` file with `@font-face` rules and classes for detected OpenType features (e.g., `.ft-liga`).
|
|
132
|
+
|
|
133
|
+
#### WOFF → SFNT (`woff2ft`) / WOFF2 → SFNT (`woff22ft`)
|
|
134
|
+
|
|
135
|
+
Converts back to the original outline type (TTF or OTF). No extra options needed.
|
|
136
|
+
|
|
137
|
+
#### TrueType Collection → SFNT (`ttc2sfnt`)
|
|
138
|
+
|
|
139
|
+
Unpacks a TTC/OTC collection into individual font files. No extra options needed.
|
|
140
|
+
|
|
141
|
+
#### Variable → Static (`var2static`)
|
|
142
|
+
|
|
143
|
+
Export named or custom variable-font instances as separate static fonts.
|
|
144
|
+
|
|
145
|
+
- **Named instances** — Pick from the font's predefined instances.
|
|
146
|
+
- **Custom instances** — Define your own axis values for any variable font.
|
|
147
|
+
- **Target UPM** — Scale the exported fonts.
|
|
148
|
+
- **Autohint** (TrueType) / **Subroutinize** (PostScript) — On by default when applicable.
|
|
149
|
+
|
|
150
|
+
## Usage
|
|
151
|
+
|
|
152
|
+
### GUI Workflow
|
|
153
|
+
|
|
154
|
+

|
|
155
|
+
|
|
156
|
+
1. **Add fonts** — Use *Add files…*, *Add folder…*, or drag and drop. The scanner inspects file contents, not extensions, so it finds fonts regardless of naming.
|
|
157
|
+
2. **Choose a profile** — The list shows how many scanned fonts are compatible with each conversion. Select a profile before converting; you can also choose one before adding fonts.
|
|
158
|
+
3. **Select fonts** — The input table shows each font's name, format, outline type, and UPM. Right-click its header to show the optional Family and Style columns; the choice is remembered, and filtering searches those fields even when hidden. Incompatibility reasons appear beside names when space permits, in tooltips, and below the table for a selected incompatible font. Use *Select compatible fonts* or *Hide incompatible* to filter.
|
|
159
|
+
4. **Set output and options** — Converted files are saved next to their sources by default. Choose a separate folder, optionally organize the output, and adjust profile-specific options. Open *Save options…* in the output card for settings shared by all conversions.
|
|
160
|
+
5. **Convert** — Check the profile, selection count, and destination in the action bar, then use the fixed *Convert* button or Ctrl+Enter. Monitor progress, pause, resume, or cancel mid-run. Afterward, use *View last run* to review or export logs, or *Open output folder* to open the last conversion's output.
|
|
161
|
+
|
|
162
|
+
For variable fonts, *Variable → Static* changes the input list to a tree of fonts and instances.
|
|
163
|
+
Select a font or instance and use *Add custom instance…*. Right-click a custom
|
|
164
|
+
instance (or press Shift+F10) to edit or remove it; Delete also removes the selected custom instance.
|
|
165
|
+
Use *View* to expand or collapse all variable fonts.
|
|
166
|
+
|
|
167
|
+
On wider windows the font list stays beside the conversion and output controls, which scroll
|
|
168
|
+
independently when needed. On narrower windows these sections stack vertically.
|
|
169
|
+
The initial theme follows the system color scheme when available; the theme toggle saves your
|
|
170
|
+
preference for future launches. Focus the theme toggle and press Space or Enter to switch themes.
|
|
171
|
+
|
|
172
|
+
Existing output files are preserved by default: a conflicting name gets a numbered suffix such as
|
|
173
|
+
`font#1.otf`. Enable **Overwrite existing files** only when replacing existing output is intended.
|
|
174
|
+
|
|
175
|
+
### Organize your output
|
|
176
|
+
|
|
177
|
+
Big batch, tidy folders. In the GUI, **Organize output…** lets you build a folder structure from
|
|
178
|
+
properties such as family, output format, outline type, UPM, tolerance, and contour simplification.
|
|
179
|
+
The available criteria depend on the conversion profile.
|
|
180
|
+
|
|
181
|
+
Add a folder level for each directory you want, then choose one or more criteria for it. Criteria
|
|
182
|
+
in the same level are joined with `_`; separate levels create nested folders. For example, putting
|
|
183
|
+
**Format** and **Outline type** in the first level and **UPM** in the second could produce:
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
opentype_ps/upm_1000/font.otf
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Use the arrows to reorder levels or criteria, and watch the example path update as you go. The
|
|
190
|
+
preview also appears below the output controls when folder levels are configured. It is
|
|
191
|
+
illustrative: actual folder and file names depend on the fonts and conversion settings.
|
|
192
|
+
Each criterion can be used once; if they're all in use, remove one before adding it elsewhere.
|
|
193
|
+
Without folder levels, files are saved directly in the chosen output location—alongside their
|
|
194
|
+
sources by default.
|
|
195
|
+
|
|
196
|
+
### CLI Usage
|
|
197
|
+
|
|
198
|
+

|
|
199
|
+
|
|
200
|
+
```console
|
|
201
|
+
# Convert all fonts in a directory to WOFF/WOFF2
|
|
202
|
+
notyafc-cli ft2wf ./fonts --recursive --output-dir ./converted
|
|
203
|
+
|
|
204
|
+
# Convert TTF to OTF with custom tolerance
|
|
205
|
+
notyafc-cli ttf2otf ./fonts --tolerance 0.5 --no-subroutinize
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Run `notyafc-cli --help` or `notyafc-cli <profile> --help` for full options.
|
|
209
|
+
Existing output files are preserved by default; use `--overwrite` to replace them explicitly.
|
|
210
|
+
|
|
211
|
+
## Advanced Settings
|
|
212
|
+
|
|
213
|
+
Options shared by all profiles:
|
|
214
|
+
|
|
215
|
+
- **Recalculate bounding boxes** — Rebuild glyph bounds before saving (on by default).
|
|
216
|
+
- **Recalculate modified timestamp** — Set a fresh modification timestamp (off by default).
|
|
217
|
+
- **Reorder tables on save** — Use a standard table order for compatibility (on by default).
|
|
218
|
+
|
|
219
|
+
## Requirements
|
|
220
|
+
|
|
221
|
+
- Python 3.11+
|
|
222
|
+
- A desktop environment supported by Qt 6 (for the GUI)
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
Clone the repository and install dependencies:
|
|
227
|
+
|
|
228
|
+
```console
|
|
229
|
+
git clone https://github.com/ftCLI/NotYAFC.git
|
|
230
|
+
cd NotYAFC
|
|
231
|
+
uv sync --group dev
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Run the test suite:
|
|
235
|
+
|
|
236
|
+
```console
|
|
237
|
+
uv run pytest
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The project uses `ruff` for linting/formatting and `mypy` for type checking. A coverage threshold of 90% is enforced.
|
|
241
|
+
|
|
242
|
+
For future packaging, use `src/font_converter/assets/notyafc.ico` as the Windows executable icon. On macOS, create an `.icns` from the individual icon sizes using system tools, without resampling the 512px image. On Linux, point the `.desktop` file to a 256px or 512px PNG. The ICO contains the optimized sizes up to 256px; the supplied `ico.png` is 512px.
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
247
|
+
|
|
248
|
+
## Acknowledgments
|
|
249
|
+
|
|
250
|
+
NotYAFC is built on top of excellent open-source tools:
|
|
251
|
+
|
|
252
|
+
- [FontTools](https://github.com/fonttools/fonttools) — Font parsing and writing
|
|
253
|
+
- [ttfautohint](https://freedesktop.org/wiki/Software/ttfautohint/) — TrueType autohinting
|
|
254
|
+
- [cffsubr](https://github.com/adobe-type-tools/cffsubr) — CFF subroutinization
|
|
255
|
+
- [Skia pathops](https://github.com/google/skia) — Contour overlap removal and winding correction
|
|
256
|
+
- DeepMind Sans by Colophon Foundry (SIL Open Font License 1.1) — The icon's letter “a” outline is derived from this font
|
notyafc-1.0.0/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# NotYAFC — Not Yet Another Font Converter
|
|
2
|
+
> A free, open-source desktop app and CLI for batch font conversion. Local, controllable, and built on trusted tools.
|
|
3
|
+
|
|
4
|
+
<p align="center">
|
|
5
|
+
<img src="https://raw.githubusercontent.com/ftCLI/NotYAFC/main/src/font_converter/assets/notyafc-1024.png" alt="NotYAFC logo" width="256" height="256">
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Tests%20%28ubuntu-latest%29&label=Tests%20%28Linux%29" alt="Tests (Linux)"></a>
|
|
10
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Tests%20%28windows-latest%29&label=Tests%20%28Windows%29" alt="Tests (Windows)"></a>
|
|
11
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Tests%20%28macos-latest%29&label=Tests%20%28macOS%29" alt="Tests (macOS)"></a>
|
|
12
|
+
<a href="https://github.com/ftCLI/NotYAFC/actions/workflows/ci.yml"><img src="https://img.shields.io/github/check-runs/ftCLI/NotYAFC/main?nameFilter=Lint%20and%20type%20check&label=Lint" alt="Lint"></a>
|
|
13
|
+
<a href="https://pypi.org/project/notyafc/"><img src="https://img.shields.io/pypi/v/notyafc?label=PyPI" alt="PyPI version"></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
NotYAFC converts fonts between formats — TrueType, PostScript, WOFF, WOFF2 — and can extract fonts from collections or export variable-font instances as static files. It runs entirely on your machine, supports batch processing, and gives you fine-grained control over every conversion parameter.
|
|
19
|
+
|
|
20
|
+
It provides two interfaces:
|
|
21
|
+
|
|
22
|
+
- **GUI** — A PySide6 desktop application with drag-and-drop, progress tracking, and per-profile options.
|
|
23
|
+
- **CLI** — A Typer-based command-line tool for scripting and repeatable workflows.
|
|
24
|
+
|
|
25
|
+
Both interfaces share the same conversion engine, so you get identical results regardless of how you use NotYAFC.
|
|
26
|
+
|
|
27
|
+
## Why NotYAFC?
|
|
28
|
+
|
|
29
|
+
- **Local** — Your fonts never leave your machine. No uploads, no online services.
|
|
30
|
+
- **Batch-ready** — Add files or entire folders, scan recursively, and convert hundreds of fonts at once.
|
|
31
|
+
- **Transparent** — Built on [FontTools](https://github.com/fonttools/fonttools), `ttfautohint`, and `cffsubr`. No black-box conversion — just a practical interface around established font tools.
|
|
32
|
+
- **Fine-grained control** — Tune curve-conversion tolerance, target UPM, contour optimization, autohinting, subroutinization, and more.
|
|
33
|
+
- **Output, organized your way** — Build a custom folder structure from font properties and conversion settings, so even large batches land where you want them.
|
|
34
|
+
- **Batch-aware** — Pause, resume, or cancel mid-run. Incompatible fonts are explained, not silently skipped.
|
|
35
|
+
- **Dual interface** — Use the GUI for interactive work or the CLI for automation.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
### With uv (recommended)
|
|
40
|
+
|
|
41
|
+
```console
|
|
42
|
+
uv tool install notyafc
|
|
43
|
+
notyafc
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Try it without installing: `uvx notyafc`. Upgrade later with `uv tool upgrade notyafc`.
|
|
47
|
+
|
|
48
|
+
The CLI is available as `notyafc-cli`. Run `notyafc-cli --help` for available commands.
|
|
49
|
+
|
|
50
|
+
### From PyPI with pip
|
|
51
|
+
|
|
52
|
+
Install the latest release from [PyPI](https://pypi.org/project/notyafc/):
|
|
53
|
+
|
|
54
|
+
**Windows (PowerShell):**
|
|
55
|
+
```powershell
|
|
56
|
+
py -m venv .venv
|
|
57
|
+
.\.venv\Scripts\Activate.ps1
|
|
58
|
+
python -m pip install notyafc
|
|
59
|
+
notyafc
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**macOS and Linux:**
|
|
63
|
+
```console
|
|
64
|
+
python3 -m venv .venv
|
|
65
|
+
source .venv/bin/activate
|
|
66
|
+
python -m pip install notyafc
|
|
67
|
+
notyafc
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
To upgrade an existing installation, run `python -m pip install --upgrade notyafc`.
|
|
71
|
+
The command-line interface is available as `notyafc-cli`; run `notyafc-cli --help` for usage.
|
|
72
|
+
|
|
73
|
+
### From source
|
|
74
|
+
|
|
75
|
+
```console
|
|
76
|
+
git clone https://github.com/ftCLI/NotYAFC.git
|
|
77
|
+
cd NotYAFC
|
|
78
|
+
uv sync
|
|
79
|
+
uv run notyafc
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Conversion Profiles
|
|
83
|
+
|
|
84
|
+
| Profile | Description |
|
|
85
|
+
|---------|-------------|
|
|
86
|
+
| `ttf2otf` | TrueType → PostScript (TTF → OTF) |
|
|
87
|
+
| `otf2ttf` | PostScript → TrueType (OTF → TTF) |
|
|
88
|
+
| `ft2wf` | SFNT → WOFF / WOFF2 webfonts |
|
|
89
|
+
| `woff2ft` | WOFF → SFNT (TTF or OTF) |
|
|
90
|
+
| `woff22ft` | WOFF2 → SFNT (TTF or OTF) |
|
|
91
|
+
| `ttc2sfnt` | TTC/OTC collection → individual fonts |
|
|
92
|
+
| `var2static` | Variable font → static instances |
|
|
93
|
+
|
|
94
|
+
### Profile Options
|
|
95
|
+
|
|
96
|
+
#### TrueType → PostScript (`ttf2otf`)
|
|
97
|
+
|
|
98
|
+
- **Tolerance** (0.1–3, default 1) — Controls curve-conversion accuracy in thousandths of an em; the actual deviation scales with UPM. Lower values allow less deviation, but may increase point count and file size.
|
|
99
|
+
- **Target UPM** — Scale the font to a chosen units-per-em value.
|
|
100
|
+
- **Simplify contours** (0–3, default 0/off) — Experimental: merge neighboring smooth curves to reduce point count. Deviation is a multiple of Tolerance.
|
|
101
|
+
- **Subroutinize** (on by default) — Compress PostScript outlines using shared subroutines.
|
|
102
|
+
|
|
103
|
+
#### PostScript → TrueType (`otf2ttf`)
|
|
104
|
+
|
|
105
|
+
- **Tolerance** (0–3, default 1) — Controls curve-conversion accuracy in thousandths of an em; the actual deviation scales with UPM. Lower values allow less deviation, but may increase point count and file size.
|
|
106
|
+
- **Target UPM** — Scale the font to a chosen units-per-em value.
|
|
107
|
+
- **Autohint** (on by default) — Add TrueType hinting instructions via `ttfautohint`.
|
|
108
|
+
|
|
109
|
+
#### SFNT → WOFF / WOFF2 (`ft2wf`)
|
|
110
|
+
|
|
111
|
+
- **Format** — Choose WOFF, WOFF2, or both (both selected by default).
|
|
112
|
+
- **Obfuscate names** — Replace family, full, and PostScript names with hashes (including in the output filename).
|
|
113
|
+
- **Remove unused glyphs** — Drop glyphs not reachable from the character map or OpenType features.
|
|
114
|
+
- **Remove non-Windows names** — Strip `name` records for platforms other than Windows (platform ID 3).
|
|
115
|
+
- **Remove DSIG table** (WOFF only) — Remove the digital signature table.
|
|
116
|
+
- **Create CSS** — Write a `fonts.css` file with `@font-face` rules and classes for detected OpenType features (e.g., `.ft-liga`).
|
|
117
|
+
|
|
118
|
+
#### WOFF → SFNT (`woff2ft`) / WOFF2 → SFNT (`woff22ft`)
|
|
119
|
+
|
|
120
|
+
Converts back to the original outline type (TTF or OTF). No extra options needed.
|
|
121
|
+
|
|
122
|
+
#### TrueType Collection → SFNT (`ttc2sfnt`)
|
|
123
|
+
|
|
124
|
+
Unpacks a TTC/OTC collection into individual font files. No extra options needed.
|
|
125
|
+
|
|
126
|
+
#### Variable → Static (`var2static`)
|
|
127
|
+
|
|
128
|
+
Export named or custom variable-font instances as separate static fonts.
|
|
129
|
+
|
|
130
|
+
- **Named instances** — Pick from the font's predefined instances.
|
|
131
|
+
- **Custom instances** — Define your own axis values for any variable font.
|
|
132
|
+
- **Target UPM** — Scale the exported fonts.
|
|
133
|
+
- **Autohint** (TrueType) / **Subroutinize** (PostScript) — On by default when applicable.
|
|
134
|
+
|
|
135
|
+
## Usage
|
|
136
|
+
|
|
137
|
+
### GUI Workflow
|
|
138
|
+
|
|
139
|
+

|
|
140
|
+
|
|
141
|
+
1. **Add fonts** — Use *Add files…*, *Add folder…*, or drag and drop. The scanner inspects file contents, not extensions, so it finds fonts regardless of naming.
|
|
142
|
+
2. **Choose a profile** — The list shows how many scanned fonts are compatible with each conversion. Select a profile before converting; you can also choose one before adding fonts.
|
|
143
|
+
3. **Select fonts** — The input table shows each font's name, format, outline type, and UPM. Right-click its header to show the optional Family and Style columns; the choice is remembered, and filtering searches those fields even when hidden. Incompatibility reasons appear beside names when space permits, in tooltips, and below the table for a selected incompatible font. Use *Select compatible fonts* or *Hide incompatible* to filter.
|
|
144
|
+
4. **Set output and options** — Converted files are saved next to their sources by default. Choose a separate folder, optionally organize the output, and adjust profile-specific options. Open *Save options…* in the output card for settings shared by all conversions.
|
|
145
|
+
5. **Convert** — Check the profile, selection count, and destination in the action bar, then use the fixed *Convert* button or Ctrl+Enter. Monitor progress, pause, resume, or cancel mid-run. Afterward, use *View last run* to review or export logs, or *Open output folder* to open the last conversion's output.
|
|
146
|
+
|
|
147
|
+
For variable fonts, *Variable → Static* changes the input list to a tree of fonts and instances.
|
|
148
|
+
Select a font or instance and use *Add custom instance…*. Right-click a custom
|
|
149
|
+
instance (or press Shift+F10) to edit or remove it; Delete also removes the selected custom instance.
|
|
150
|
+
Use *View* to expand or collapse all variable fonts.
|
|
151
|
+
|
|
152
|
+
On wider windows the font list stays beside the conversion and output controls, which scroll
|
|
153
|
+
independently when needed. On narrower windows these sections stack vertically.
|
|
154
|
+
The initial theme follows the system color scheme when available; the theme toggle saves your
|
|
155
|
+
preference for future launches. Focus the theme toggle and press Space or Enter to switch themes.
|
|
156
|
+
|
|
157
|
+
Existing output files are preserved by default: a conflicting name gets a numbered suffix such as
|
|
158
|
+
`font#1.otf`. Enable **Overwrite existing files** only when replacing existing output is intended.
|
|
159
|
+
|
|
160
|
+
### Organize your output
|
|
161
|
+
|
|
162
|
+
Big batch, tidy folders. In the GUI, **Organize output…** lets you build a folder structure from
|
|
163
|
+
properties such as family, output format, outline type, UPM, tolerance, and contour simplification.
|
|
164
|
+
The available criteria depend on the conversion profile.
|
|
165
|
+
|
|
166
|
+
Add a folder level for each directory you want, then choose one or more criteria for it. Criteria
|
|
167
|
+
in the same level are joined with `_`; separate levels create nested folders. For example, putting
|
|
168
|
+
**Format** and **Outline type** in the first level and **UPM** in the second could produce:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
opentype_ps/upm_1000/font.otf
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use the arrows to reorder levels or criteria, and watch the example path update as you go. The
|
|
175
|
+
preview also appears below the output controls when folder levels are configured. It is
|
|
176
|
+
illustrative: actual folder and file names depend on the fonts and conversion settings.
|
|
177
|
+
Each criterion can be used once; if they're all in use, remove one before adding it elsewhere.
|
|
178
|
+
Without folder levels, files are saved directly in the chosen output location—alongside their
|
|
179
|
+
sources by default.
|
|
180
|
+
|
|
181
|
+
### CLI Usage
|
|
182
|
+
|
|
183
|
+

|
|
184
|
+
|
|
185
|
+
```console
|
|
186
|
+
# Convert all fonts in a directory to WOFF/WOFF2
|
|
187
|
+
notyafc-cli ft2wf ./fonts --recursive --output-dir ./converted
|
|
188
|
+
|
|
189
|
+
# Convert TTF to OTF with custom tolerance
|
|
190
|
+
notyafc-cli ttf2otf ./fonts --tolerance 0.5 --no-subroutinize
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Run `notyafc-cli --help` or `notyafc-cli <profile> --help` for full options.
|
|
194
|
+
Existing output files are preserved by default; use `--overwrite` to replace them explicitly.
|
|
195
|
+
|
|
196
|
+
## Advanced Settings
|
|
197
|
+
|
|
198
|
+
Options shared by all profiles:
|
|
199
|
+
|
|
200
|
+
- **Recalculate bounding boxes** — Rebuild glyph bounds before saving (on by default).
|
|
201
|
+
- **Recalculate modified timestamp** — Set a fresh modification timestamp (off by default).
|
|
202
|
+
- **Reorder tables on save** — Use a standard table order for compatibility (on by default).
|
|
203
|
+
|
|
204
|
+
## Requirements
|
|
205
|
+
|
|
206
|
+
- Python 3.11+
|
|
207
|
+
- A desktop environment supported by Qt 6 (for the GUI)
|
|
208
|
+
|
|
209
|
+
## Development
|
|
210
|
+
|
|
211
|
+
Clone the repository and install dependencies:
|
|
212
|
+
|
|
213
|
+
```console
|
|
214
|
+
git clone https://github.com/ftCLI/NotYAFC.git
|
|
215
|
+
cd NotYAFC
|
|
216
|
+
uv sync --group dev
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Run the test suite:
|
|
220
|
+
|
|
221
|
+
```console
|
|
222
|
+
uv run pytest
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The project uses `ruff` for linting/formatting and `mypy` for type checking. A coverage threshold of 90% is enforced.
|
|
226
|
+
|
|
227
|
+
For future packaging, use `src/font_converter/assets/notyafc.ico` as the Windows executable icon. On macOS, create an `.icns` from the individual icon sizes using system tools, without resampling the 512px image. On Linux, point the `.desktop` file to a 256px or 512px PNG. The ICO contains the optimized sizes up to 256px; the supplied `ico.png` is 512px.
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
232
|
+
|
|
233
|
+
## Acknowledgments
|
|
234
|
+
|
|
235
|
+
NotYAFC is built on top of excellent open-source tools:
|
|
236
|
+
|
|
237
|
+
- [FontTools](https://github.com/fonttools/fonttools) — Font parsing and writing
|
|
238
|
+
- [ttfautohint](https://freedesktop.org/wiki/Software/ttfautohint/) — TrueType autohinting
|
|
239
|
+
- [cffsubr](https://github.com/adobe-type-tools/cffsubr) — CFF subroutinization
|
|
240
|
+
- [Skia pathops](https://github.com/google/skia) — Contour overlap removal and winding correction
|
|
241
|
+
- DeepMind Sans by Colophon Foundry (SIL Open Font License 1.1) — The icon's letter “a” outline is derived from this font
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "NotYAFC"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Not Yet Another Font Converter: a free and open-source font converter for desktop and command-line use, written in Python."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"cffsubr>=0.4.0",
|
|
9
|
+
"fonttools[pathops,woff]>=4.68.0",
|
|
10
|
+
"pathvalidate>=3.3.1",
|
|
11
|
+
"PySide6>=6.8",
|
|
12
|
+
"typer==0.28.0",
|
|
13
|
+
"ttfautohint-py>=0.6.1",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[[project.authors]]
|
|
17
|
+
name = "Cesare Gilento"
|
|
18
|
+
email = "ftCLI@proton.me"
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
notyafc-cli = "font_converter.cli:main"
|
|
22
|
+
|
|
23
|
+
[project.gui-scripts]
|
|
24
|
+
notyafc = "font_converter.__main__:main"
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = [
|
|
28
|
+
"pytest>=9.1.1",
|
|
29
|
+
"pytest-cov>=7.1.0",
|
|
30
|
+
"ruff>=0.16.10",
|
|
31
|
+
"mypy>=2.4.0",
|
|
32
|
+
"bandit[toml]>=1.9.4",
|
|
33
|
+
"pip-audit>=2.10.1",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
testpaths = ["tests"]
|
|
38
|
+
addopts = "--cov=font_converter --cov-report=term-missing:skip-covered --cov-fail-under=90"
|
|
39
|
+
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
target-version = "py311"
|
|
42
|
+
line-length = 100
|
|
43
|
+
src = ["src"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff.lint]
|
|
46
|
+
select = [
|
|
47
|
+
"E",
|
|
48
|
+
"F",
|
|
49
|
+
"I",
|
|
50
|
+
"UP",
|
|
51
|
+
"B",
|
|
52
|
+
"C4",
|
|
53
|
+
"SIM",
|
|
54
|
+
]
|
|
55
|
+
ignore = ["E501"]
|
|
56
|
+
|
|
57
|
+
[tool.ruff.format]
|
|
58
|
+
quote-style = "double"
|
|
59
|
+
indent-style = "space"
|
|
60
|
+
|
|
61
|
+
[tool.mypy]
|
|
62
|
+
python_version = "3.11"
|
|
63
|
+
files = ["src"]
|
|
64
|
+
warn_unused_configs = true
|
|
65
|
+
check_untyped_defs = true
|
|
66
|
+
ignore_missing_imports = true
|
|
67
|
+
|
|
68
|
+
[tool.uv.build-backend]
|
|
69
|
+
module-name = "font_converter"
|
|
70
|
+
|
|
71
|
+
[build-system]
|
|
72
|
+
requires = ["uv_build>=0.12.23,<0.14.0"]
|
|
73
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "NotYAFC"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Not Yet Another Font Converter: a free and open-source font converter for desktop and command-line use, written in Python."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Cesare Gilento", email = "ftCLI@proton.me" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"cffsubr>=0.4.0",
|
|
12
|
+
"fonttools[pathops,woff]>=4.68.0",
|
|
13
|
+
"pathvalidate>=3.3.1",
|
|
14
|
+
"PySide6>=6.8",
|
|
15
|
+
"typer==0.28.0",
|
|
16
|
+
"ttfautohint-py>=0.6.1",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
notyafc-cli = "font_converter.cli:main"
|
|
21
|
+
|
|
22
|
+
[project.gui-scripts]
|
|
23
|
+
notyafc = "font_converter.__main__:main"
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"pytest>=9.1.1",
|
|
28
|
+
"pytest-cov>=7.1.0",
|
|
29
|
+
"ruff>=0.16.10",
|
|
30
|
+
"mypy>=2.4.0",
|
|
31
|
+
"bandit[toml]>=1.9.4",
|
|
32
|
+
"pip-audit>=2.10.1",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[tool.pytest.ini_options]
|
|
36
|
+
testpaths = ["tests"]
|
|
37
|
+
addopts = "--cov=font_converter --cov-report=term-missing:skip-covered --cov-fail-under=90"
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
target-version = "py311"
|
|
41
|
+
line-length = 100
|
|
42
|
+
src = ["src"]
|
|
43
|
+
|
|
44
|
+
[tool.ruff.lint]
|
|
45
|
+
select = ["E", "F", "I", "UP", "B", "C4", "SIM"]
|
|
46
|
+
ignore = ["E501"]
|
|
47
|
+
|
|
48
|
+
[tool.ruff.format]
|
|
49
|
+
quote-style = "double"
|
|
50
|
+
indent-style = "space"
|
|
51
|
+
|
|
52
|
+
[tool.mypy]
|
|
53
|
+
python_version = "3.11"
|
|
54
|
+
files = ["src"]
|
|
55
|
+
warn_unused_configs = true
|
|
56
|
+
check_untyped_defs = true
|
|
57
|
+
ignore_missing_imports = true
|
|
58
|
+
|
|
59
|
+
[build-system]
|
|
60
|
+
requires = ["uv_build>=0.12.23,<0.14.0"]
|
|
61
|
+
build-backend = "uv_build"
|
|
62
|
+
|
|
63
|
+
[tool.uv.build-backend]
|
|
64
|
+
module-name = "font_converter"
|