How to split a font file to multiple parts?

1k views Asked by At

How to split a font file to multiple parts automatically?

Why do I need this? Because as up to Chrome 99, it limits maximum uncompressed file size of a font to 30 MB. See https://chromium.googlesource.com/external/ots/+/v6.1.1/src/ots.cc

Additionally, Chinese fonts often excceed 30 MB per file. For example, CNS11643 fonts: https://data.gov.tw/dataset/5961

Thus, I need an automation tool to split a font file.

1

There are 1 answers

0
Meng-Yuan Huang On BEST ANSWER

FontForge app supports Python scripting, which can be used to achieve automatic font splitting.

This is an example script 2.

import glob
import os
import fontforge

# Up to Chrome 99, the max uncompressed size (e.g. ttf) of a font file is 30 MB.
# Please tune this value to split a font file to multiple files with size <= 30 MB.
maxGlyphsPerFile = 15000
# The glob expression of all font files.
fontFilesPath = "../fonts/*.ttf"

def splitFontFile(originalFile):
    filename = os.path.basename(file)
    filename = filename.split('.')[0]
    font = fontforge.open(originalFile)
    font.selection.all()
    glyphs = font.selection.byGlyphs
    totalGlyphs = len(list(glyphs))
    totalFiles = int(totalGlyphs / maxGlyphsPerFile + 0.5)
    print(f'{file} totalFiles: {totalFiles}')

    for f in range(totalFiles):
        g = 0
        gMin = f * maxGlyphsPerFile
        gMax = (f + 1) * maxGlyphsPerFile
        for glyph in glyphs:
            # Clear glyph out of range.
            if not(gMin <= g and g < gMax):
                glyph.clear()
            g = g + 1
        # Use this to check uncompressed font file sizes.
        #font.generate(f'{filename}-{f+1}.ttf')
        # Use this for compressed outputs.
        font.generate(f'{filename}-{f+1}.woff2')
        font.close()
        font = fontforge.open(originalFile)
        font.selection.all()
        glyphs = font.selection.byGlyphs
    font.close()
    
for file in glob.glob(fontFilesPath):
    splitFontFile(file)
    print('Done!')