foliojs / fontkit

An advanced font engine for Node and the browser
1.44k stars 210 forks source link

Filling gaps in one font with glyphs from another to create a hybrid font #295

Closed kckern closed 10 months ago

kckern commented 1 year ago

Suppose I am using a weird font with missing glyphs (apostrophe’s, colons, other punctuation, special chars, etc) and I want to fill its gaps with glyphs from a more complete font.

I would need to:

  1. Identify if the weird font contains the glyph in question
  2. If no, extract the glyph from the normal font
  3. Replace the empty slot in the weird font with the glyph from the normal font
  4. Save the fixed font as its own TTF.
const fs = require('fs');
const fontkit = require('fontkit');

// Load two fonts: a normal one and a weird one.
var normalFont = fontkit.openSync(`normal.ttf`);
var weirdFont = fontkit.openSync(`weird.ttf`);

// Does weirdFont have an apostrophe (') glyph?
const specialChar = "'";
var weirdFontLayout = weirdFont.layout(specialChar);
if(weirdFontLayout.glyphs[0].id===0) // weirdFont DOES NOT have an apostrophe (')
{
    // Extract an apostrophe from a normal font
    var normalFontLayout = normalFont.layout(specialChar);
    var normalFontGlyph = normalFontLayout.glyphs[0];

    // ???? How to inject the normal glyph into the weird font ????
    weirdFont.replaceEmptyGlyphWith(normalFontGlyph);

     // Save edited weird font as TTF
    fs.writeFileSync('weird_fixed.ttf', weirdFont.stream.buffer);

}

So how would I go about with weirdFont.replaceEmptyGlyphWith(normalFontGlyph)?

Pomax commented 1 year ago

Given that there is no guarantee that the font metrics would be even remotely similar, you'd probably have to do a fair bit of work based on getting the various metrics (both font global and specific to that glyph) for both fonts so you can match one to the other. This is something that might feel like it should be straight forward, but is actually a lot of work in terms of making sure the replacements look right =)

kckern commented 1 year ago

Thanks for the response. Since posting, I've dug in a bit more. Seems like the best route might be to convert ttf to a SVG font, and add glyphs and adjust metrics as needed just with XML manipulation, then convert it back to ttf.

Pomax commented 1 year ago

That's an option, although you'll still need to perform the metrics matching there, too (so you don't end up with a full stop that's the size of a lowercase O, or positioned halfway up the main font's ascender because the two fonts have different baselines, for example).

Although at that point you're also just "creating a new font" by mashing two fonts together, rather than relying on font stack logic, so I guess the question is "what are you actually doing" (i.e. what kind of thing are you trying to implement, in which tech stack. Because useful as fontkit is, it might not actually be the right tool for the job)