Skip to content

Commit

Permalink
Match glyph names between fonts
Browse files Browse the repository at this point in the history
  • Loading branch information
simoncozens committed Sep 5, 2024
1 parent 307a07f commit f618a68
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/bin/ttj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ fn main() {
let name = matches.get_one::<String>("font").expect("No font name?");
let font_binary = std::fs::read(name).expect("Couldn't open file");
let font = FontRef::new(&font_binary).expect("Can't parse");
let json = font_to_json(&font);
let json = font_to_json(&font, None);
println!("{:}", serde_json::to_string_pretty(&json).unwrap());
}
62 changes: 50 additions & 12 deletions src/ttj/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::ttj::jsondiff::diff;
use crate::ttj::serializefont::ToValue;
use read_fonts::tables::{self};
use read_fonts::traversal::SomeTable;
use read_fonts::{FontRef, TableProvider};
use serde_json::{Map, Value};
Expand Down Expand Up @@ -47,23 +46,29 @@ fn gid_to_name<'a>(font: &impl TableProvider<'a>, gid: GlyphId) -> String {
format!("gid{:}", gid)
}

fn serialize_cmap_table<'a>(font: &impl TableProvider<'a>) -> Value {
fn serialize_cmap_table<'a>(font: &impl TableProvider<'a>, names: &[String]) -> Value {
let charmap = Charmap::new(font);
let mut map = Map::new();
for (codepoint, glyph_id) in charmap.mappings() {
let name = gid_to_name(font, glyph_id);
let mut map: Map<String, Value> = Map::new();
for (codepoint, gid) in charmap.mappings() {
let name = names
.get(gid.to_u32() as usize)
.map(|n| n.to_string())
.unwrap_or_else(|| format!("gid{}", gid));
map.insert(format!("U+{:04X}", codepoint), Value::String(name));
}
Value::Object(map)
}

fn serialize_hmtx_table<'a>(font: &impl TableProvider<'a>) -> Value {
fn serialize_hmtx_table<'a>(font: &impl TableProvider<'a>, names: &[String]) -> Value {
let mut map = Map::new();
if let Ok(hmtx) = font.hmtx() {
let widths = hmtx.h_metrics();
let long_metrics = widths.len();
for gid in 0..font.maxp().unwrap().num_glyphs() {
let name = gid_to_name(font, GlyphId::new(gid as u32));
let name = names
.get(gid as usize)
.map(|n| n.to_string())
.unwrap_or_else(|| format!("gid{}", gid));
if gid < (long_metrics as u16) {
if let Some((width, lsb)) = widths
.get(gid as usize)
Expand All @@ -89,7 +94,14 @@ fn serialize_hmtx_table<'a>(font: &impl TableProvider<'a>) -> Value {
Value::Object(map)
}

pub fn font_to_json(font: &FontRef) -> Value {
pub fn font_to_json(font: &FontRef, glyphmap: Option<&[String]>) -> Value {
let glyphmap = if let Some(glyphmap) = glyphmap {
glyphmap
} else {
&(0..font.maxp().unwrap().num_glyphs())
.map(|gid| gid_to_name(font, GlyphId::new(gid as u32)))
.collect::<Vec<String>>()
};
let mut map = Map::new();

for table in font.table_directory.table_records().iter() {
Expand Down Expand Up @@ -119,7 +131,7 @@ pub fn font_to_json(font: &FontRef) -> Value {
// b"cmap" => font.cmap().map(|t| <dyn SomeTable>::serialize(&t)),
// b"GDEF" => font.gdef().map(|t| <dyn SomeTable>::serialize(&t)),
// b"GPOS" => font.gpos().map(|t| <dyn SomeTable>::serialize(&t)),
b"GSUB" => font.gsub().map(|t| <dyn SomeTable>::serialize(&t)),
// b"GSUB" => font.gsub().map(|t| <dyn SomeTable>::serialize(&t)),
b"COLR" => font.colr().map(|t| <dyn SomeTable>::serialize(&t)),
b"CPAL" => font.cpal().map(|t| <dyn SomeTable>::serialize(&t)),
b"STAT" => font.stat().map(|t| <dyn SomeTable>::serialize(&t)),
Expand All @@ -140,16 +152,42 @@ pub fn font_to_json(font: &FontRef) -> Value {
// }
}
map.insert("name".to_string(), serialize_name_table(font));
map.insert("cmap".to_string(), serialize_cmap_table(font));
map.insert("hmtx".to_string(), serialize_hmtx_table(font));
map.insert("cmap".to_string(), serialize_cmap_table(font, glyphmap));
map.insert("hmtx".to_string(), serialize_hmtx_table(font, glyphmap));
map.insert("GDEF".to_string(), gdef::serialize_gdef_table(font));
map.insert("GPOS".to_string(), layout::serialize_gpos_table(font));
map.insert("GSUB".to_string(), layout::serialize_gsub_table(font));
Value::Object(map)
}

pub fn table_diff(font_a: &FontRef, font_b: &FontRef) -> Value {
diff(&font_to_json(font_a), &font_to_json(font_b))
let glyphmap_a: Vec<String> = (0..font_a.maxp().unwrap().num_glyphs())
.map(|gid| gid_to_name(font_a, GlyphId::new(gid as u32)))
.collect();
let glyphmap_b: Vec<String> = (0..font_b.maxp().unwrap().num_glyphs())
.map(|gid| gid_to_name(font_b, GlyphId::new(gid as u32)))
.collect();
let count_glyphname_differences = glyphmap_a
.iter()
.zip(glyphmap_b.iter())
.filter(|(a, b)| a != b)
.count();
let big_difference = count_glyphname_differences > glyphmap_a.len() / 2;
if big_difference {
println!("Glyph names differ dramatically between fonts, using font names from font A");
}

diff(
&font_to_json(font_a, Some(&glyphmap_a)),
&font_to_json(
font_b,
Some(if big_difference {
&glyphmap_a
} else {
&glyphmap_b
}),
),
)
}

// fn main() {
Expand Down

0 comments on commit f618a68

Please sign in to comment.