Merging multiple Noto fonts to single TTF font
This is a tutorial-style article on how to generate a big, single font file (.ttf) which combines multiple language fonts. The reason is that Google’s Noto Fonts are mostly distributed as separate files for each language or script. In this article, I’ll describe the steps to generate a single combined TTF for most Indian languages. The steps are specific to Debian, but you can adjust it for other distros or language families.
Note that there is a technical limitation that a single font file cannot contain more than 65,535 glyphs. So you cannot apply this technique for all the fonts, but it works well for Indic languages whose combined total glyph count is far less than that.
See below for Downloads.
What is your goal?
The goal is to generate a single font file containing all these scripts:
- Latin, Greek, Cyrillic and others contained in NotoSans-Regular.ttf
- Devanagari (used for Sanskrit, Hindi, Marathi, Nepali, etc.)
- Bengali (used for Bengali and Assamese)
- Gurmukhi (used for Punjabi)
- Gujarati
- Oriya (used for Odia)
- Tamil
- Telugu
- Kannada
- Malayalam
- Sinhala
- Brahmi
- Saurashtra
- Kaithi
- Lepcha
- Limbu
- Meetei Mayek
- Ol Chiki
What do you need?
If you’re on Debian/Ubuntu:
apt install python3-nototools fonttools
If you can’t do the above, you can manually clone the
nototools repository. You’re going to
use the merge_fonts.py
script.
Fonttools is only needed if you want to change the name of the final merged font.
How to do it?
First make a copy of merge_fonts.py
since you don’t have permission to edit the one in /usr
:
cp /usr/lib/python3/dist-packages/nototools/merge_fonts.py /tmp/merge_fonts.py
Edit that script and adjust the files
variable to contain the list of all the fonts that you want
to combine:
files = [
# It's recommended to put NotoSans-Regular.ttf as the first element in the
# list to maximize the amount of meta data retained in the final merged font.
"NotoSans-Regular.ttf",
"NotoSansDevanagari-Regular.ttf",
"NotoSansBengali-Regular.ttf",
"NotoSansGurmukhi-Regular.ttf",
"NotoSansGujarati-Regular.ttf",
"NotoSansOriya-Regular.ttf",
"NotoSansTamil-Regular.ttf",
"NotoSansTelugu-Regular.ttf",
"NotoSansKannada-Regular.ttf",
"NotoSansMalayalam-Regular.ttf",
"NotoSansSinhala-Regular.ttf",
"NotoSansBrahmi-Regular.ttf",
"NotoSansKaithi-Regular.ttf",
"NotoSansLepcha-Regular.ttf",
"NotoSansLimbu-Regular.ttf",
"NotoSansMeeteiMayek-Regular.ttf",
"NotoSansOlChiki-Regular.ttf",
"NotoSansSaurashtra-Regular.ttf",
]
I’ve chosen only the Regular
font-weight as example, but you can choose Bold
fonts as well.
The names of the files must match the ones you’ve downloaded in your font directory. You can download them from GitHub NotoFonts if you’ve not done so already. Or you can invoke apt:
apt install fonts-noto-core # or fonts-noto-hinted in older distros
which fecthes pretty much all the important fonts (except CJK and Emojis) and places them in
/usr/share/fonts/truetype/noto/
.
And the magic happens:
cd /usr/lib/python3/dist-packages/nototools # whichever dir contains merge_noto.py
PYTHONPATH='.' python3 /tmp/merge_fonts.py -d /usr/share/fonts/truetype/noto/ -o /tmp/NotoSansIndic.ttf
WARNING:fontTools.fixedTools:Table version value is a float: 1.0000; fix to use hex instead: 0x00010000
Merging 18 Fonts...
18 fonts are merged. 0 fonts are skipped. Cost 558.813 s.
Please check the result at /tmp/NotoSansIndic.ttf.
The conversion process will take some time (~10 min). The combined TTF is about 1.8 MB containing about 10,100 glyphs.
The script accepts two options: -d
points to the directory containing .ttf files and -o
is the
output file name of the merged font. The script merge_fonts.py
internally calls merge_noto.py
;
hence you adjust PYTHONPATH
to include that dir. Both .py are originally in same directory anyway
but you’ve modified only merge_fonts.py
.
Renaming your font
The name and attributes of the merged font is inherited from whatever was the first in files
list
(see above). In your case, the merged font is still called “Noto Sans Regular” – it will cause
confusion after installation because you might have another font with the same name already
installed as part of fonts-noto-core
package. So you’ve to change the name of the generated font.
Fonttools can be used for this purpose:
apt install fonttools
It installs a tool called ttx
which creates a text file
from a .ttf font:
ttx /tmp/NotoSansIndic.ttf
The text file has .ttx extension and you can open it in your $EDITOR
. Do a simple Find-Replace. In
my case, I replaced “Noto Sans” with “Noto Sans Indic”:
sed -i "s/Noto Sans/Noto Sans Indic/g" /tmp/NotoSansIndic.ttx
sed -i "s/NotoSans/NotoSansIndic/g" /tmp/NotoSansIndic.ttx
The ttx
command is smart enough to do the reverse too: throw it a .ttx file and it will generate
the corresponding .ttf:
ttx /tmp/NotoSansIndic.ttx
Compiling "/tmp/NotoSansIndic.ttx" to "/tmp/NotoSansIndic#1.ttf"...
And that’s it! The font NotoSansIndic#1.ttf
is ready to be installed.
Download
I scaled the above logic to combine more than 70 fonts! You can download the merged font (Noto Indosphere ttf) here – it contains all the Brahmic scripts, including historical ones – used in India, South Asia and South East Asia; plus Nastaliq (Persian/Urdu) script, Munda languages, LGC (Latin-Greek-Cyrillic) blocks, lots of symbols, maths notation and emojis too! There are 13000+ Unicode code points spanning 36000+ glyphs in just ~ 6.6 MB. You can think of it as a “Pan-Unicode font”.
NOTE:
- Use
otfinfo
to count the number of glyphs and code points. unitettc
converts TTF to/from TTC (True Type Collection of ttfs).pyftmerge
andpyftsubset
are CLI tools part of fonttools package which, respectively, merge fonts and create subsets of fonts.