diff --git a/fonts/ClickerScript-Regular.ttf b/fonts/ClickerScript-Regular.ttf deleted file mode 100644 index 8bbf9731..00000000 Binary files a/fonts/ClickerScript-Regular.ttf and /dev/null differ diff --git a/fonts/LatinModernRoman-Regular.otf b/fonts/LatinModernRoman-Regular.otf deleted file mode 100644 index 6a96b468..00000000 Binary files a/fonts/LatinModernRoman-Regular.otf and /dev/null differ diff --git a/fonts/NewCMMath-Regular.otf b/fonts/NewCMMath-Regular.otf deleted file mode 100644 index 82221fb8..00000000 Binary files a/fonts/NewCMMath-Regular.otf and /dev/null differ diff --git a/fonts/NotoSansCJKsc-Regular.otf b/fonts/NotoSansCJKsc-Regular.otf deleted file mode 100644 index dc155624..00000000 Binary files a/fonts/NotoSansCJKsc-Regular.otf and /dev/null differ diff --git a/ft.sh b/ft.sh index 7c3d72cb..3b07c285 100755 --- a/ft.sh +++ b/ft.sh @@ -1,4 +1,4 @@ fonttools subset fonts/NotoSans-Regular.ttf --drop-tables=GSUB,GPOS,GDEF \ - --gids=80-100,3,4,10,30,31,300-330 --glyph-names --output-file=out_ft.ttf \ - --notdef-outline --no-prune-unicode-ranges --name-IDs='*' + --gids=5,6,9,10 --glyph-names --output-file=out_ft.ttf \ + --notdef-outline --no-prune-unicode-ranges fonttools ttx -f -o out_ft.ttx out_ft.ttf \ No newline at end of file diff --git a/src/cmap.rs b/src/cmap.rs index 60ef0eda..c401f874 100644 --- a/src/cmap.rs +++ b/src/cmap.rs @@ -228,7 +228,7 @@ pub(crate) fn subset(ctx: &mut Context) -> Result<()> { } } - if subsetted_subtables.len() == 0 { + if subsetted_subtables.len() == 0 && num_tables != 0 { // The font only contains non-Unicode subtables. return Err(Error::Unimplemented); } diff --git a/src/lib.rs b/src/lib.rs index 396e285f..76b96fa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ mod head; mod hhea; mod hmtx; mod maxp; +mod name; mod post; mod stream; @@ -318,6 +319,7 @@ impl<'a> Context<'a> { Tag::POST => post::subset(self)?, Tag::CMAP => cmap::subset(self)?, Tag::MAXP => maxp::subset(self)?, + Tag::NAME => name::subset(self)?, _ => self.push(tag, data), } @@ -328,8 +330,6 @@ impl<'a> Context<'a> { let mut original_gids = self.subset.iter().collect::>(); original_gids.sort(); - println!("{:?}", original_gids); - let mut counter = 0; for gid in original_gids { self.gid_map.insert(*gid, counter); diff --git a/src/main.rs b/src/main.rs index 9c5fbe41..7d33ba59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,7 @@ fn main() { // Keep only three glyphs and the OpenType tables // required for embedding the font in a PDF file. let mut glyphs = vec![]; - glyphs.extend(80..=100); - glyphs.extend([3, 4, 10, 30, 31]); - glyphs.extend(300..=330); + glyphs.extend([5, 6, 9, 10]); let profile = Profile::pdf(&glyphs); let sub = subset(&data, 0, profile).unwrap(); diff --git a/src/name.rs b/src/name.rs new file mode 100644 index 00000000..d16fb1a9 --- /dev/null +++ b/src/name.rs @@ -0,0 +1,124 @@ +use super::*; + +struct NameRecord { + platform_id: u16, + encoding_id: u16, + language_id: u16, + name_id: u16, + length: u16, + string_offset: u16, +} + +impl NameRecord { + fn is_unicode(&self) -> bool { + self.platform_id == 0 + || (self.platform_id == 3 && [0, 1, 10].contains(&self.encoding_id)) + } +} + +impl Structure<'_> for NameRecord { + fn read(r: &mut Reader<'_>) -> Result { + let platform_id = r.read::()?; + let encoding_id = r.read::()?; + let language_id = r.read::()?; + let name_id = r.read::()?; + let length = r.read::()?; + let string_offset = r.read::()?; + + Ok(Self { + platform_id, + encoding_id, + language_id, + name_id, + length, + string_offset, + }) + } + + fn write(&self, w: &mut Writer) { + w.write::(self.platform_id); + w.write::(self.encoding_id); + w.write::(self.language_id); + w.write::(self.name_id); + w.write::(self.length); + w.write::(self.string_offset); + } +} + +pub(crate) fn subset(ctx: &mut Context) -> Result<()> { + let name = ctx.expect_table(Tag::NAME)?; + let mut r = Reader::new(name); + + // From the over 3k font (variations) I had locally, none had version 1. + // So we only focus on subsetting version 0 and on the off-chance + // that a font has version 1, we just add it as is. + let version = r.read::()?; + + if version != 0 { + ctx.push(Tag::NAME, name); + return Ok(()); + } + + let count = r.read::()?; + r.read::()?; // storage offset + + let mut name_records = vec![]; + + for _ in 0..count { + name_records.push(r.read::()?); + } + + let storage = r.data(); + + let mut pruned = prune_name_records(name_records); + + if pruned.len() == 0 && count != 0 { + // Only contains non-Unicode records, so we don't subset. + ctx.push(Tag::NAME, name); + return Ok(()); + } + + let mut sub_name = Writer::new(); + let mut new_storage = Writer::new(); + let mut cur_storage_offset = 0; + + let count = pruned.len() as u16; + + // version + sub_name.write::(0); + // count + sub_name.write::(count); + // storage offset + sub_name.write::(2 * 3 + count * 12); + + for record in &mut pruned { + new_storage.give( + &storage[(record.string_offset as usize) + ..((record.string_offset + record.length) as usize)], + ); + record.string_offset = cur_storage_offset; + sub_name.write_ref::(record); + cur_storage_offset += record.length; + } + + sub_name.give(&new_storage.finish()); + + ctx.push(Tag::NAME, sub_name.finish()); + Ok(()) +} + +fn prune_name_records(name_records: Vec) -> Vec { + let mut pruned = vec![]; + + for record in name_records { + if record.is_unicode() { + // TODO: Determine which exact records we need. But the PDF reference + // doesn't seem to indicate anything about this. + if [0, 1, 2, 3, 4, 5, 6].contains(&record.name_id) { + pruned.push(record); + } + } + } + + pruned +} diff --git a/src/post.rs b/src/post.rs index 5c907bb4..b3cb89a7 100644 --- a/src/post.rs +++ b/src/post.rs @@ -30,7 +30,6 @@ pub(crate) fn subset(ctx: &mut Context) -> Result<()> { } let num_glyphs = ctx.subset.len() as u16; - println!("{:?}", num_glyphs); // Start writing a new subsetted post table. let mut sub_post = Writer::new();