foliojs / fontkit

An advanced font engine for Node and the browser
1.45k stars 213 forks source link

How to combine multiple language fonts using Fontkit? #247

Open lancejpollard opened 3 years ago

lancejpollard commented 3 years ago

Hi there, I am trying to combine several language fonts into one font, selecting only the letters I need for the final font, but I'm not sure how to do this. Any help would be appreciated.


const fontkit = require('fontkit')
const fs = require('fs')

const fonts = {
  amharic: fontkit.openSync('stack/build/text/screen/amharic.otf'),
  arabic: fontkit.openSync('stack/build/text/screen/arabic.otf'),
  aramaic: fontkit.openSync('stack/build/text/screen/aramaic.otf'),
  armenian: fontkit.openSync('stack/build/text/screen/armenian.otf'),
  avestan: fontkit.openSync('stack/build/text/screen/avestan.otf'),
  bengali: fontkit.openSync('stack/build/text/screen/bengali.otf'),
  canadian: fontkit.openSync('stack/build/text/screen/canadian.otf'),
  cherokee: fontkit.openSync('stack/build/text/screen/cherokee.otf'),
  chinese: fontkit.openSync('stack/build/text/screen/chinese-(simplified).otf'),
  coptic: fontkit.openSync('stack/build/text/screen/coptic.otf'),
  cuneiform: fontkit.openSync('stack/build/text/screen/cuneiform.otf'),
  devanagari: fontkit.openSync('stack/build/text/screen/devanagari.otf'),
  egyptian: fontkit.openSync('stack/build/text/screen/egyptian.otf'),
  emoji: fontkit.openSync('stack/build/text/screen/emoji.otf'),
  etruscan: fontkit.openSync('stack/build/text/screen/etruscan.otf'),
  georgian: fontkit.openSync('stack/build/text/screen/georgian.otf'),
  gothic: fontkit.openSync('stack/build/text/screen/gothic.otf'),
  gujarati: fontkit.openSync('stack/build/text/screen/gujarati.otf'),
  gurmukhi: fontkit.openSync('stack/build/text/screen/gurmukhi.otf'),
  hebrew: fontkit.openSync('stack/build/text/screen/hebrew.otf'),
  japanese: fontkit.openSync('stack/build/text/screen/japanese.otf'),
  javanese: fontkit.openSync('stack/build/text/screen/javanese.otf'),
  kannada: fontkit.openSync('stack/build/text/screen/kannada.otf'),
  khmer: fontkit.openSync('stack/build/text/screen/khmer.otf'),
  korean: fontkit.openSync('stack/build/text/screen/korean.otf'),
  latin: fontkit.openSync('stack/build/text/screen/latin.otf'),
  lepcha: fontkit.openSync('stack/build/text/screen/lepcha.otf'),
  malayalam: fontkit.openSync('stack/build/text/screen/malayalam.otf'),
  mongolian: fontkit.openSync('stack/build/text/screen/mongolian.otf'),
  myanmar: fontkit.openSync('stack/build/text/screen/myanmar.otf'),
  ogham: fontkit.openSync('stack/build/text/screen/ogham.otf'),
  oriya: fontkit.openSync('stack/build/text/screen/oriya.otf'),
  osage: fontkit.openSync('stack/build/text/screen/osage.otf'),
  pahlavi: fontkit.openSync('stack/build/text/screen/pahlavi.otf'),
  phoenician: fontkit.openSync('stack/build/text/screen/phoenician.otf'),
  runic: fontkit.openSync('stack/build/text/screen/runic.otf'),
  samaritan: fontkit.openSync('stack/build/text/screen/samaritan.otf'),
  sinhala: fontkit.openSync('stack/build/text/screen/sinhala.otf'),
  sundanese: fontkit.openSync('stack/build/text/screen/sundanese.otf'),
  syriac: fontkit.openSync('stack/build/text/screen/syriac-(eastern).otf'),
  syriac: fontkit.openSync('stack/build/text/screen/syriac-(western).otf'),
  tagalog: fontkit.openSync('stack/build/text/screen/tagalog.otf'),
  tamil: fontkit.openSync('stack/build/text/screen/tamil.otf'),
  telugu: fontkit.openSync('stack/build/text/screen/telugu.otf'),
  thai: fontkit.openSync('stack/build/text/screen/thai.otf'),
  tibetan: fontkit.openSync('stack/build/text/screen/tibetan.otf'),
  tifinagh: fontkit.openSync('stack/build/text/screen/tifinagh.otf'),
  ugaritic: fontkit.openSync('stack/build/text/screen/ugaritic.otf'),
  vai: fontkit.openSync('stack/build/text/screen/vai.otf'),
  yi: fontkit.openSync('stack/build/text/screen/yi.otf')
}

const { latin } = fonts

const TEXT = `English
中文བོད་སྐདसंस्कृतम्
עבריתالعربيةதமிழ்ᐃᓄᒃᑎᑐᑦ日本語
한국어සිංහලမြန်မာဘာသာবাংলা
ქართულიગુજરાતીΕλληνικά
ꦧꦱꦗꦮລາວไทยᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔
తెలుగుአማርኛՀայերենଓଡ଼ିଆ
ਪੰਜਾਬੀРусскийᮘᮞ ᮞᮥᮔ᮪ᮓSuomi
FrançaisGàidhligGaeilge
هَوُسَIgboisiXhosaYorùbá
isiZuluMagyarDansk
EuskaraEnglisc
Sinugboanong Binisaya
ÍslenskaItalianoLatinaNorsk
OromooPolskiCusco QuechuachiShona
SoomaaliEspañolKiswahili
SvenskaTiếng ViệtCymraeg
অসমীয়াཇོང་ཁमराठीनेपाली
Монголپښتوትግርኛ
Українська
اردوفارسیहिन्दी`.replace(/\s+/g, '').split('')

const subset = latin.createSubset()

getAllGlyphs().forEach(glyph => {
  console.log(glyph)
  subset.includeGlyph(glyph)
})

subset.encodeStream()
  .pipe(fs.createWriteStream('stack/build/text/screen/heading.ttf'))

function getAllGlyphs() {
  let glyphs = []
  for (let key in fonts) {
    glyphs.push.apply(glyphs, getGlyphs(fonts[key]))
  }
  return glyphs
}

function getGlyphs(font) {
  return TEXT.filter(x => {
    return font.hasGlyphForCodePoint(x.codePointAt(0))
  }).map(x => {
    return font.glyphForCodePoint(x.codePointAt(0))
  })
}

What I have doesn't work, I get an error which seems to suggest my characters are out of range of the latin font. It seems I need to start with a "unicode 100%" font, and then take a subset of that, how do I do that?

Thank you!

TypeError: Cannot read property 'offset' of undefined
    at CFFFont.getCharString (/Users/me/code/app/leaf.surf/node_modules/fontkit/index.js:2003:55)
    at CFFSubset.subsetCharstrings (/Users/me/code/app/leaf.surf/node_modules/fontkit/index.js:13411:38)
    at CFFSubset.encode (/Users/me/code/app/leaf.surf/node_modules/fontkit/index.js:13546:10)
    at /Users/me/code/app/leaf.surf/node_modules/fontkit/index.js:13048:13