Expand description
OpenType font subsetting.
This is a simple, no-std-compatible library that provides OpenType font subsetting, i.e.,
retaining only glyphs and other related data that correspond to specific chars. The subset can then be
saved in the OpenType (.otf / .ttf) or WOFF2 format.
As an example, it is possible to subset visible ASCII chars (' '..='~') from a font that originally supported
multiple languages. Subsetting may lead to significant space savings; e.g., a subset of Roboto (the standard
sans-serif font for Android) with visible ASCII chars occupies just 19 kB in the OpenType format
(and 11 kB in the WOFF2 format) vs the original 457 kB.
The motivating use case for this library is embedding the produced font as a data URL in HTML or SVG, so that it’s guaranteed to be rendered in the same way across platforms.
§Features
- Can read and write fonts to/from OpenType and WOFF2 (the latter via an opt-in crate feature).
- Supports variable fonts. This allows to embed a continuous set of fonts across one or more dimensions, such as font weight or width, into a single file.
- Provides general info about fonts, e.g., font naming / license info and variation axis parameters.
- Single dependency for WOFF2 (de)compression; no-std compatible.
§Design philosophy
- Keep parsing simple. The library generally assumes that the input is well-formed, and defers parsing when possible. For example, simple glyph data is not parsed at all because it’s not necessary for subsetting; it can be copied as opaque bytes.
- Keep focus. The library is focused on subsetting. For example, it doesn’t strive to parse all tables from the OpenType spec.
- Keep dependencies lean. The library has the only opt-in dependency (
brotli) to support WOFF2 serialization. The library is unconditionally no-std-compatible.
§Known limitations
- Subsetting drops advanced layout tables like
GPOS,kernetc. - Some table data (e.g.,
maxpfields like “maximum points in a non-composite glyph”) are not updated in the subset font. Looks like some other subsetters (e.g.,allsorts) do not update them either.
§Alternatives and similar tools
allsortsis a library working with OpenType / WOFF / WOFF2 fonts, including their subsetting. It’s more versatile, but at the cost of having more deps and requiring the standard library (although there is a no-std fork). Its subsetting logic also produces fonts not parseable by browsers because of a missingOS/2table.subsetteris a specialized subsetting library. but it’s geared towards PDF subsetting specifically (i.e., again not covering the motivating SVG use case).
§Crate features
§std
(On by default)
Enables std-specific functionality, such as Error trait implementations for error types.
§woff2
(Off by default)
Enables writing fonts in the WOFF2 format.
§tracing
(Off by default)
Enables logging / tracing via the tracing facade, mostly on the DEBUG and TRACE levels.
§Examples
§Subsetting
use font_subset::{Font, FontReader};
let font_bytes = // font in the OpenType or WOFF2 format
// Create a font reader. This starts parsing and, in case of WOFF2,
// decompresses the font data.
let reader = FontReader::new(font_bytes)?;
// Parse the font from the reader.
let font: Font<'_> = reader.read()?;
// Ensure that the font license permits embedding and subsetting.
let permissions = font.permissions();
assert!(permissions.embedding.is_lenient());
assert!(permissions.allow_subsetting);
let retained_chars: BTreeSet<char> = (' '..='~').collect();
// Create a subset.
let subset = font.subset(&retained_chars)?;
// Serialize the subset in OpenType and WOFF2 formats.
let ttf: Vec<u8> = subset.to_opentype();
println!("OpenType size: {}", ttf.len());
let woff2: Vec<u8> = subset.to_woff2();
println!("WOFF2 size: {}", woff2.len());§Getting info about font
use font_subset::OpenTypeReader;
let font_bytes = // font in the OpenType format
let font_reader = OpenTypeReader::new(font_bytes)?;
for (table, bytes) in font_reader.raw_tables() {
println!("{table} length: {} B", bytes.len());
}
// Parse the font to get table-specific info.
let font = font_reader.read()?;
println!("Name: {:?}", font.naming().family);
println!("Subfamily: {:?}", font.naming().subfamily);
println!("License: {:?}", font.naming().license);
let covered_chars: Vec<_> = font.char_ranges().collect();
println!("Covered chars: {covered_chars:?}");
println!("Glyph count: {}", font.glyph_count());
let variation_axes = font.variation_axes().unwrap_or(&[]);
for axis in variation_axes {
println!("Variation axis: {:?} [{}]", axis.name, axis.tag);
println!(
"Range: {:?} (default: {})",
axis.min_value..=axis.max_value,
axis.default_value
);
}Structs§
- Fixed
- Fixed-point signed 32-bit value. Used in
VariableAxisparams. - Font
- Shallowly parsed OpenType font.
- Font
Metrics - Basic font metrics.
- Font
Naming - OpenType font naming information extracted from the
nametable. - Long
Date Time - Signed 64-bit timestamps used in some tables, in particular, for
Font::created_at()andFont::modified_at(). - Open
Type Reader - Reader for OpenType files (
.otf/.ttf). Borrows data from an external source. - Owned
Font - Version of
Fontthat owns its data. - Parse
Error - Errors that can occur when parsing an OpenType
Font. - Table
Tag - 4-byte tag of an OpenType font table.
- Usage
Permissions - Usage permissions for a font recorded in its OS/2 table.
- Variation
Axis - Information about a variation axis of a variable font.
- Variation
Axis Tag - Tag of a
VariationAxis. - Warning
- Warning that can occur validating a font.
- Warnings
- Set of
Warnings. - Woff2
Reader woff2 - Reader for files in the WOFF2 format.
Enums§
- Embedding
Permissions - Embedding permissions recorded in the OS/2 font table.
- File
Format - Supported font formats.
- Font
Category - Basic font face category.
- Font
Reader - Generic font reader that auto-detects the file format based on its first bytes.
- Parse
Error Kind - Kind of a font
ParseError. - Warning
Kind - Kind of a
Warning.