Skip to main content

Crate font_subset

Crate font_subset 

Source
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, kern etc.
  • Some table data (e.g., maxp fields 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

  • allsorts is 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 missing OS/2 table.
  • subsetter is 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 VariableAxis params.
Font
Shallowly parsed OpenType font.
FontMetrics
Basic font metrics.
FontNaming
OpenType font naming information extracted from the name table.
LongDateTime
Signed 64-bit timestamps used in some tables, in particular, for Font::created_at() and Font::modified_at().
OpenTypeReader
Reader for OpenType files (.otf / .ttf). Borrows data from an external source.
OwnedFont
Version of Font that owns its data.
ParseError
Errors that can occur when parsing an OpenType Font.
TableTag
4-byte tag of an OpenType font table.
UsagePermissions
Usage permissions for a font recorded in its OS/2 table.
VariationAxis
Information about a variation axis of a variable font.
VariationAxisTag
Tag of a VariationAxis.
Warning
Warning that can occur validating a font.
Warnings
Set of Warnings.
Woff2Readerwoff2
Reader for files in the WOFF2 format.

Enums§

EmbeddingPermissions
Embedding permissions recorded in the OS/2 font table.
FileFormat
Supported font formats.
FontCategory
Basic font face category.
FontReader
Generic font reader that auto-detects the file format based on its first bytes.
ParseErrorKind
Kind of a font ParseError.
WarningKind
Kind of a Warning.