tangled
alpha
login
or
join now
lem.my
/
rubify
0
fork
atom
Annotate fonts with ruby (pinyin/romaji) and produce modified TTF/WOFF2 outputs.
0
fork
atom
overview
issues
pulls
pipelines
fix: ttc output
lem.my
1 month ago
0b1bf2cb
6042aab7
verified
This commit was signed with the committer's
known signature
.
lem.my
SSH Key Fingerprint:
SHA256:bngDbnD0BlRUkDO6ExMr630lPO0g478ldQSe7Es/gR4=
+38
-53
2 changed files
expand all
collapse all
unified
split
src
lib.rs
main.rs
+36
-46
src/lib.rs
reviewed
···
1
1
pub mod renderer;
2
2
3
3
-
use anyhow::{Context, Result, anyhow};
3
3
+
use anyhow::{Context, Result};
4
4
use fontcull_font_types::NameId;
5
5
use fontcull_klippa::{Plan, SubsetFlags, subset_font};
6
6
use fontcull_read_fonts::{
···
11
11
};
12
12
use fontcull_skrifa::{MetadataProvider, outline::OutlinePen};
13
13
use fontcull_write_fonts::{
14
14
-
FontBuilder, dump_table,
15
15
-
from_obj::{FromObjRef, ToOwnedObj},
14
14
+
FontBuilder,
15
15
+
from_obj::ToOwnedObj,
16
16
tables::{
17
17
glyf::{Glyf, GlyfLocaBuilder, Glyph, SimpleGlyph},
18
18
head::Head,
19
19
loca::Loca,
20
20
-
name::Name,
21
20
},
22
21
};
23
22
use indicatif::ProgressStyle;
24
23
use kurbo::BezPath;
25
24
use rayon::iter::{ParallelBridge, ParallelIterator};
26
25
use rustc_hash::FxHashMap;
27
27
-
use tracing::info_span;
26
26
+
use tracing::{info, info_span};
28
27
use tracing_indicatif::span_ext::IndicatifSpanExt;
29
28
use woofwoof;
30
29
31
30
use crate::renderer::RubyRenderer;
32
31
33
33
-
pub fn process_font_file(file: FileRef, renderer: &Box<dyn RubyRenderer>) -> Result<Vec<u8>> {
32
32
+
pub fn process_font_file(
33
33
+
file: FileRef,
34
34
+
renderer: &Box<dyn RubyRenderer>,
35
35
+
subset: bool,
36
36
+
) -> Result<Vec<u8>> {
34
37
match file {
35
35
-
FileRef::Font(font) => process_single_font(font, &renderer),
36
36
-
FileRef::Collection(collection) => {
37
37
-
let head = collection
38
38
-
.iter()
39
39
-
.next()
40
40
-
.context("No fonts in collection")??;
38
38
+
FileRef::Font(font) => {
39
39
+
let data = process_font_ref(font, &renderer)?;
41
40
42
42
-
let family_name = get_family_name(&head).unwrap();
41
41
+
if subset {
42
42
+
info!("Subsetting font...");
43
43
44
44
+
subset_by_renderers(&data, &renderer)
45
45
+
} else {
46
46
+
Ok(data)
47
47
+
}
48
48
+
}
49
49
+
FileRef::Collection(collection) => {
44
50
let collection_span = info_span!("process_fonts_in_collection");
45
51
collection_span.pb_set_style(
46
52
&ProgressStyle::with_template("{msg} [{wide_bar:.green/cyan}] {pos}/{len}")
···
59
65
60
66
let font = font.context("Failed to read font")?;
61
67
62
62
-
let data = process_single_font(font, &renderer)?;
68
68
+
let mut data = process_font_ref(font, &renderer)?;
69
69
+
70
70
+
if subset {
71
71
+
info!("Subsetting font...");
72
72
+
data = subset_by_renderers(&data, &renderer)?;
73
73
+
}
74
74
+
63
75
let data = Box::leak(data.into_boxed_slice());
64
76
65
77
FontRef::new(data).context("Failed to create font ref")
···
68
80
69
81
drop(process_span_enter);
70
82
71
71
-
build_ttc(&fonts, &family_name)
83
83
+
build_ttc(&fonts)
72
84
}
73
85
}
74
86
}
75
87
76
76
-
fn process_single_font(font: FontRef, renderer: &Box<dyn RubyRenderer>) -> Result<Vec<u8>> {
88
88
+
pub fn process_font_ref(font: FontRef, renderer: &Box<dyn RubyRenderer>) -> Result<Vec<u8>> {
77
89
let font_file_data = font.table_directory.offset_data();
78
90
let charmap = font.charmap();
79
91
let hmtx = font.hmtx()?;
···
214
226
}
215
227
216
228
pub fn subset_by_renderers(font_data: &[u8], renderer: &Box<dyn RubyRenderer>) -> Result<Vec<u8>> {
217
217
-
let file = FileRef::new(font_data).context("Failed to parse font for subsetting")?;
218
218
-
let font = file
219
219
-
.fonts()
220
220
-
.next()
221
221
-
.context("No font found for subsetting")?
222
222
-
.context("Read error")?;
229
229
+
let font = FontRef::new(font_data).context("Failed to parse font for subsetting")?;
223
230
224
231
// Build unicodes set based on provided character sets
225
232
let mut unicodes = IntSet::<u32>::empty();
···
295
302
}
296
303
}
297
304
298
298
-
pub fn build_ttc(fonts: &[FontRef], family_name: &str) -> Result<Vec<u8>> {
305
305
+
pub fn build_ttc(fonts: &[FontRef]) -> Result<Vec<u8>> {
299
306
let mut out = Vec::new();
300
307
301
308
// TTC header
···
331
338
332
339
for record in records {
333
340
let tag = record.tag();
334
334
-
let mut data = font
341
341
+
let table_data = font
335
342
.table_data(tag)
336
343
.context("Table missing")?
337
344
.as_ref()
338
345
.to_vec();
339
346
340
340
-
// Rewrite name table
341
341
-
if tag == Name::TAG {
342
342
-
let name_table = font.name()?;
343
343
-
let mut new_name = Name::from_obj_ref(&name_table, font.data());
344
344
-
345
345
-
for rec in new_name.name_record.iter_mut() {
346
346
-
match rec.name_id {
347
347
-
NameId::FAMILY_NAME => {
348
348
-
rec.string = family_name.to_string().into();
349
349
-
}
350
350
-
_ => {}
351
351
-
}
352
352
-
}
353
353
-
354
354
-
data = dump_table(&new_name)?;
355
355
-
}
356
356
-
357
347
// Only share tables that are usually safe and heavy
358
348
let can_share = matches!(tag, Glyf::TAG | Cff::TAG | Loca::TAG);
359
349
360
350
let rel_offset = if can_share {
361
361
-
if let Some(&off) = table_cache.get(&(tag, data.clone())) {
351
351
+
if let Some(&off) = table_cache.get(&(tag, table_data.clone())) {
362
352
off
363
353
} else {
364
354
while table_data_block.len() % 4 != 0 {
···
366
356
}
367
357
368
358
let off = table_data_block.len() as u32;
369
369
-
table_cache.insert((tag, data.clone()), off);
370
370
-
table_data_block.extend(&data);
359
359
+
table_cache.insert((tag, table_data.clone()), off);
360
360
+
table_data_block.extend(&table_data);
371
361
372
362
off
373
363
}
···
377
367
}
378
368
379
369
let off = table_data_block.len() as u32;
380
380
-
table_data_block.extend(&data);
370
370
+
table_data_block.extend(&table_data);
381
371
382
372
off
383
373
};
···
385
375
out.extend_from_slice(&tag.to_be_bytes());
386
376
out.extend_from_slice(&record.checksum().to_be_bytes());
387
377
out.extend_from_slice(&rel_offset.to_be_bytes());
388
388
-
out.extend_from_slice(&(data.len() as u32).to_be_bytes());
378
378
+
out.extend_from_slice(&(table_data.len() as u32).to_be_bytes());
389
379
}
390
380
}
391
381
+2
-7
src/main.rs
reviewed
···
22
22
#[facet(args::named, args::short = 'o')]
23
23
out: PathBuf,
24
24
25
25
-
/// Optional font file to use for ruby characters
25
25
+
/// Separate font file to use for ruby characters
26
26
#[facet(args::named)]
27
27
font: Option<PathBuf>,
28
28
···
245
245
}
246
246
};
247
247
248
248
-
let mut new_font_data = rubify::process_font_file(base_file, &renderer)?;
249
249
-
250
250
-
if cli.subset {
251
251
-
info!("Subsetting font...");
252
252
-
new_font_data = rubify::subset_by_renderers(&new_font_data, &renderer)?;
253
253
-
}
248
248
+
let mut new_font_data = rubify::process_font_file(base_file, &renderer, cli.subset)?;
254
249
255
250
// let extension = out_path
256
251
// .extension()