1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! 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](https://crates.io/crates/allsorts_no_std)).
//! 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.
//!
//! [variable fonts]: https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview
//! [`brotli`]: https://crates.io/crates/brotli
//! [`allsorts`]: https://crates.io/crates/allsorts
//! [`subsetter`]: https://crates.io/crates/subsetter
//!
//! # Examples
//!
//! ## Subsetting
//!
//! ```
//! # use std::collections::BTreeSet;
//! use font_subset::{Font, FontReader};
//!
//! let font_bytes = // font in the OpenType or WOFF2 format
//! # include_bytes!("../examples/FiraMono-Regular.ttf");
//! // 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());
//! # assert!(ttf.len() < 20 * 1_024);
//!
//! let woff2: Vec<u8> = subset.to_woff2();
//! println!("WOFF2 size: {}", woff2.len());
//! # assert!(woff2.len() < 15 * 1_024);
//! # Ok::<_, font_subset::ParseError>(())
//! ```
//!
//! ## Getting info about font
//!
//! ```
//! use font_subset::OpenTypeReader;
//!
//! let font_bytes = // font in the OpenType format
//! # include_bytes!("../examples/RobotoMono-VariableFont_wght.ttf");
//! 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
//! );
//! }
//! # Ok::<_, font_subset::ParseError>(())
//! ```
// Documentation settings.
pub use crateWoff2Reader;
pub use crate::;
doctest!;