Reducing CFF font size trick

I discovered this by chance yesterday:

1. Generate CFF OTF font from FontLab Studio (or try the font creation tool of your choice; I'd be interested to hear results of this trick on fonts made with other tools).

2. Open the font in DTL OTMaster, and go to the CFF table glyph list. Scroll down to the end, and right click to 'Grow' the list. This will add a new glyph to the end of the list. Now delete the glyph that you just created. [The purpose of this is to register to OTMaster that the CFF table has been edited. If the table is not changed, OTMaster will not rewrite it.]

3. Save As under some new name. Compare the size of the original file to the new one saved from OTMaster.

I found that the font saved from OTMaster was considerably smaller than that generated by FontLab Studio. As far as I can tell, this must be due to better optimisation in OTMaster's CFF code.

I tried this on a fairly large, c.700k math font, and saved almost 100k with this process.

Comments

  • Hin-Tak Leung
    Hin-Tak Leung Posts: 363
    edited February 2016
    I'd be interested to see a detailed analysis of where the saving is. Failing that, do you mind uploading/sharing the two, before and after, to get my hand dirty?

    If you can't share the fonts but you or somebody you trust is up for it, you can insert a 'WriteLine()' inside 'CheckForNoOverlap' near 

    https://github.com/HinTak/Font-Validator/commit/14b1d65df929bb833c6c2066a924327fb0a4c4b2

    to print the calling arguments, and run it through to analyze the CFF table. That routine is used for, well, check for overlap, and receive information about where which parts start and size within the CFF table.

    OTOH, it is difficult to think of it as a lossless operation from 700k to 100k. If it happens at the glyph level, the actual curves, etc must have changed. What may be possible as a lossless operation at the glyph level, is some level of abstraction to re-factor glyphs to use Subrs, but that's assuming a lot of cleverness in the software, and possibly also specific to how the font was generated/written in the first place I.e. The font was poorly optimized in the first place, or this is a 'bug-fix' which later version of this software correcting earlier inefficiencies of itself.
  • ttx will also produce this kind of file size reduction. https://github.com/googlei18n/compreffor also helps
  • John Hudson
    John Hudson Posts: 3,230
    edited February 2016
    Hin-Tak, the font in question will be open source, but I don't want to upload it anywhere yet, since it is still in pre-release testing and I wouldn't want a stray version floating around. I will email you the two fonts, though (to the address you use for the OT list).

    I'd misremembered the exact file size difference, it is:
    FLS = 747kb
    OTM = 686kb

    So a 61kb reduction.

    This particular test differed a bit from the steps described above, because I actually removed two empty glyphs from the end of the CFF table. This is how I discovered the behaviour: FLS had added a CR and NULL glyph to the end of the font (despite the option to do so being disabled), so I used OTMaster to get rid of them. Then I noticed the big file size reduction. I'm pretty sure two empty glyphs didn't account for 61kb!


    The outlines appear to be identical. I opened the OTM font in FLS and did an overlay comparison with my original VFB source file.

    _____

    I've found the reproduction of the steps a bit unpredictable. One font this evening produced no change in font size, although it was nearly identical to one that produced a change yesterday.


  • @John Hudson : thanks for the two font files. I finished looking at them and the size difference is entirely because the newer version has an empty globalsubr and no private subr. Those two are both roughly 30k each in the old version. There is also a 2k difference in the charstrings, which I think is the deleted glyphs.

    So I think the reason for a size saving is probably quite mundane rather than some cleverness in refactoring the charstrings. The software used to create the font likely pre-populate the two subroutine indexes with some template useful stuff, assuming they will be useful and used gradually as you add more and more glyphs. When you start to delete glyphs (maybe this need deleting more than 1 glyphs to trigger), your editing software - which may or may not be the same as the one which created the font in the first place - noticed that some subroutines are simply not used and so skip putting them in the output. In this case, the whole of both are gone.

    The software used to create the font in the first place probably has a 60k min size for a new font with no glyphs :). And how much you can save this way, depends on whether you use any of the subroutines.

    I have added some code to the CFFInfo tool to show the size and offset of various things, along the line I describe earlier. Doing '-v -v ' shows them as 'Region-<what>: <offset> <size>' , in the next version. I'll push the code out to github now and send you a binary via e-mail.
  • John Hudson
    John Hudson Posts: 3,230
    edited February 2016
    Thanks a lot for the helpful analysis, Hin-Tak. It is reassuring to know where the size reduction comes from, and that it is indeed lossless in terms of outline quality and other things that matter.
  • How about in comparison to Adobe FDK makeotf?