What's new?
- Reimplemented parsing of VFB files, retired old `VfbReader` class in favour of new `Vfb` class
- Implement UFO-like interface directly to the `Vfb` class, as far as needed for `draw()`/`drawPoints()` on the glyph class
- Implement compilation and esp. glyph compilation to facilitate write access via `getPen()`/`getPointPen()` on the glyph class
- Disambiguate duplicate glyph names
- Support VFB files written by FontLab 3
- Fix encoding of manual name table entries for the Mac platform
- Raise exceptions when a file exists, or when decompilation fails
- `vfb2json`: New JSON structure for export, which allows to selectively decompile data entries while keeping others as binary
- `vfb2json`: Default output file now gets `.vfb.json` suffix
- `vfb2json`: Add option to only parse the VFB header (`-h`/`--header`)
- `vfb3ufo`: Build UFOs in memory with `ufoLib2` instead of using `UfoWriter` directly
- `vfb3ufo`: Set previously missing Glyph.height
- `vfb3ufo`: Support writing `.ufoz`
- `vfb3ufo`: Add option to interpret strings as UTF-8 instead of Windows-1252 (`-u`/`--unicode`)
- `vfbcu2qu`: New command line script to convert VFBs to TrueType (quadratic) curves
Install or update [vfbLib via pip](https://pypi.org/project/vfbLib/).
TrueType conversion
VFBs can now be directly converted to TrueType, using the industry-standard [cu2qu](https://github.com/fonttools/fonttools/tree/main/Lib/fontTools/cu2qu) library.
plain
$ vfbcu2qu -h
usage: vfbcu2qu [-h] [-p PATH] [-fo] [-m MAX_ERR_EM] inputpath [outputpath]
VFB Cubic to Quadratic Converter Copyright (c) 2023 by LucasFonts Build 2023-07-19
positional arguments:
inputpath input file path (.vfb)
outputpath output file path (.vfb)
options:
-h, --help show this help message and exit
-p PATH, --path PATH output folder
-fo, --force-overwrite
force overwrite
-m MAX_ERR_EM, --max-err-em MAX_ERR_EM
Maximum allowed error, relative to the font's units per em.
Improved UFO workflow
If you are using a UFO workflow, but don’t want to save the UFOs converted from a VFB to disk, you can now keep them in memory. This new functionality uses the `ufoLib2` library, a new dependency.
Read and convert a VFB like this:
python
from vfbLib.vfb.vfb import Vfb
from vfbLib.ufo.builder import VfbToUfoBuilder
vfb = Vfb("path/to/my.vfb")
ufo_builder = VfbToUfoBuilder(vfb)
Save UFOs and Designspace document, as before ...
ufo_builder.write("path/to/my.ufo")
Writes "path/to/my.ufo"
"path/to/my-1.ufo"
"path/to/my-2.ufo"
"path/to/my-3.ufo"
"path/to/my.designspace"
(for a VFB with 4 masters)
... or convert in memory and do something with the UFOs and designspace:
ufos, ds = ufo_builder.get_ufos_designspace("path/to/my.ufo")
The out_path is only used to construct the source paths inside the designspace document.
... or, if you only need the UFOs:
ufos = ufo_builder.get_ufo_masters()
Using pens on VFBs
You can now draw glyphs from VFBs directly to an object supporting the pen protocol, e.g. in a DrawBot script:
python
from vfbLib.vfb.vfb import Vfb
size(1000, 1000)
vfb_path = "vfbLib/Tests/Data/ComicJensPro-Regular.vfb"
vfb = Vfb(vfb_path)
g = vfb["Adieresis"]
bez = BezierPath()
g.drawPoints(bez)
drawPath(bez)
You can also draw into the Vfb by requesting a pen from a glyph, but this currently only supports TrueType curves:
python
from vfbLib.vfb.vfb import Vfb
vfb_path = "vfbLib/Tests/Data/ComicJensPro-Regular.vfb"
vfb = Vfb(vfb_path)
g = vfb["a"]
g.clearContours()
pen = g.getPointPen()
pen.beginPath()
pen.addPoint((92, 0), "line", False, None)
pen.addPoint((92, 698), "line", False, None)
pen.addPoint((277, 698), "line", False, None)
pen.addPoint((336, 698), None, False, None)
pen.addPoint((419, 657), None, False, None)
pen.addPoint((461, 579), None, False, None)
pen.addPoint((461, 526), "qcurve", False, None)
pen.addPoint((461, 471), None, False, None)
pen.addPoint((420, 391), None, False, None)
pen.addPoint((381, 371), "qcurve", False, None)
pen.addPoint((416, 363), None, False, None)
pen.addPoint((472, 314), None, False, None)
pen.addPoint((502, 242), None, False, None)
pen.addPoint((502, 200), "qcurve", False, None)
pen.addPoint((502, 138), None, False, None)
pen.addPoint((451, 47), None, False, None)
pen.addPoint((358, 0), None, False, None)
pen.addPoint((296, 0), "qcurve", False, None)
pen.endPath()
vfb.write("vfbLib/Tests/Data/ComicJensPro-Regular_modified.vfb")