Does TTX merge have an upper limit of complexity? Failing to merge large COLR table into a variable font. #2374
-
I am currently working on a color font project in which I generate a pretty large When I use The thing is, I was previously able to do this merge operation successfully – when using slightly fewer alternate glyphs in the font and a If this is a matter of exceeding a complexity limit, is there some way to work around that limitation? $ ttx -m variable-font.ttf COLR-patch.ttx
Compiling "COLR-patch.ttx" to "variable-font.ttf"...
Parsing 'COLR' table...
ERROR: Unhandled exception has occurred
Traceback (most recent call last):
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttx.py", line 401, in main
process(jobs, options)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttx.py", line 374, in process
action(input, output, options)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/misc/loggingTools.py", line 372, in wrapper
return func(*args, **kwds)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttx.py", line 292, in ttCompile
ttf.save(output)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 172, in save
writer_reordersTables = self._save(tmp)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 212, in _save
self._writeTable(tag, writer, done, tableCache)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 634, in _writeTable
tabledata = self.getTableData(tag)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 652, in getTableData
return self.tables[tag].compile(self)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/C_O_L_R_.py", line 82, in compile
table.compile(writer, ttFont)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 771, in compile
conv.write(writer, font, table, value)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 613, in write
value.compile(subWriter, font)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 735, in compile
conv.writeArray(writer, font, table, value)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 197, in writeArray
self.write(writer, font, tableDict, value, i)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 492, in write
value.compile(writer, font)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 771, in compile
conv.write(writer, font, table, value)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 278, in write
writer.writeUShort(value)
File "/Users/stephennixon/color-font-project/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 465, in writeUShort
assert 0 <= value < 0x10000, value
AssertionError: (65536, 'int', 16384, 'BaseGlyphRecord[]', 'BaseGlyphRecordArray') |
Beta Was this translation helpful? Give feedback.
Replies: 8 comments
-
Reading the COLR spec and fonttools code, it seems that the total number of layers used by the font is limited to 65536. The numLayerRecords field is 16 bit, as well as the firstLayerIndex field of BaseGlyphRecord (from https://docs.microsoft.com/en-us/typography/opentype/spec/colr) (Btw. this is unrelated to how you assemble the font: the fact that you use |
Beta Was this translation helpful? Give feedback.
-
Ahhh, okay, I’m sorry for missing what now seems to be a pretty obvious thing. Thank you so much for taking the time to let me know, @justvanrossum! I think this is my first time encountering a 16-bit limit in making a font! 65536 always seemed like such a massive number, but I guess not always. Just to make sure I understand: am I correct in assuming that there isn’t some clever way to expand or exceed that limit? Or, if I did find a way, that the font would be liable to break due to breaking the spec? Later yesterday, I did find that if I limit the character set in the font before generating & attempting to merge the COLR table, things work just fine. So, this is probably a matter of understanding the maths to determine the max complexity of COLR for a given number of input glyphs. |
Beta Was this translation helpful? Give feedback.
-
(I haven't run into this particular 16-bit limitation before, and tbh I was not aware of it until today.)
I don't think so. In theory color glyphs can point to overlapping sets of layers, but that doens't appear a very practical thing to me. Eg. if you have layers A, B, C, D, E, F, glyph 1 could use layers A, B, C, D, E and glyph 2 could use B, C, D, E, F. I can't think of a design in which that can be useful, though. |
Beta Was this translation helpful? Give feedback.
-
FWIW, in the proposed COLR version 1 table, the LayerList can contain up to 4,294,967,296 unique layers since the numLayers field is a 32-bit unsigned integer.
Indeed, that's true for both COLR v0 and v1 (via PaintColrLayers paint format, which defines slices of layers to be taken from the global LayerList). In FontTools, when compiling COLRv1 we try to reuse overlapping layers (see |
Beta Was this translation helpful? Give feedback.
-
plus, COLRv1 color glyphs are structured as directed acyclic graphs with theoretically unlimited depth so the number of unique "layers" is virtually infinite |
Beta Was this translation helpful? Give feedback.
-
Thanks for the additional details, @anthrotype!
Wow, what an amazing document. 😳 Approximately how long does it take for such upgrades to make their way into practical usage? Even as a guess, would it be likely more or less than 5 years for the As for the logic behind my immediate exploration... I am referencing the same layer glyphs multiple times, but in connection to alternate base glyphs and pointing to different colors in the I think the math basically works out to be |
Beta Was this translation helpful? Give feedback.
-
Btw. @arrowtype are you aware that you can build COLR/CPAL fonts with fontmake directly from ufos with layers? All it takes is to add some ufo2ft lib keys. |
Beta Was this translation helpful? Give feedback.
-
This is news to me, but awesome! Looks like the technique described here (googlefonts/ufo2ft#359) is probably the way to do it? |
Beta Was this translation helpful? Give feedback.
Reading the COLR spec and fonttools code, it seems that the total number of layers used by the font is limited to 65536.
The numLayerRecords field is 16 bit, as well as the firstLayerIndex field of BaseGlyphRecord (from https://docs.microsoft.com/en-us/typography/opentype/spec/colr)
(Btw. this is unrelated to how you assemble the font: the fact that you use
ttx -m
does not seem to be relevant)