Glyph width with TTX

Hello all, 

I am trying to accomplish what I thought would be a fairly easy task. I'd like to export the glyph width (as measured from leftmost to rightmost node, without advance width) from a font. 

The OTMaster shows these values in the CFF table. I thought I would see them with TTX too, but there only seem to be values related to hinting. I used the command ttx -t "CFF " /pathtofont and it seemed to work, but in the ttx file I can't find any node coordinates that I see in OTMaster. Can someone point me in the right direction? Thanks! :)
Tagged:

Comments

  • Hmm, I think what you are after is in general a calculated value, not actually stored within the CFF (whereas the advanced width is stored in hdmx). However, you could use this to get at it:

    http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_Get_CBox

    Or with the equivalent python binding of this freetype routine.
  • I think that TTX isn't the right tool for this; it's couple of lines of python in most editors. In Robofab lingo:

    font = CurrentFont()
    for glyph in font:
        print glyph.name + ': ' + str(glyph.box[2] - glyph.box[0])
  • Hm, I was under the impression that TTX output would be similar if not identical to OTMaster. I need to extract the widths of certain glyphs from a lot of fonts (80-100), so throwing them in the Terminal looked like a good time saving solution to me, rather than writing down OTMaster values.

    I must add that I couldn't code to save my life, Ben's Code gives me an error (CurrentFont not defined) in both Glyphs and FontLab and I don't know how to fix it :(


  • I don't think ttx does derived values of that 'deeper' nature - I had some c# code which get at the cbox with freetype, when I was going down the wrong path trying the re-implement the hdmx/ltsh/vdmx table verification in the microsoft font validator. It stands to reason that advanced width are useful (for fast layout, pending parallelised rendering of individual glyphs) and therefore stored pre-calculated, but caching the cbox isn't too useful.

    What platform are you on?
  • To use Ben's code in FL or Glyphs you need to add (as the first line):
    from robofab.world import CurrentFont

    In Glyphs you need to check if RoboFab is installed (Preferences/AddOns/Modules).
    For FL you also have to make sure that RoboFab is installed.
  • In pure FontLab code the following will work like charm (tested on Windows). Change the parameters as you see fit. It will generate a CSV file, with the necessary data, containing the Font Name, followed by the bounding box widths of the desired glyphs. Note that although, the CSV may look messy (using dictionaries always ends like this) all the info will land exactly in it's place.

    #FLM: Extract glyph bounds
    #by Vassil Kateliev (2016)
    
    # - Dependancies
    import os, csv
    from FL import *
    
    # - Init
    
    # List of RAW paths to typefaces. NOTE: Do not forget the r before '' ex: r'path-to-file'
    fontList = [r'D:\2_Uplink\fls2A71.otf',
    			r'D:\2_Uplink\fls7F54.otf']
    
    # RAW path to file, change it to whatever you like
    fileNameCSV = r'D:\extractor-report.csv'
    
    # List containing glyphsNames of interest
    glyphList = ['H', 'O', 'n', 'o']
    
    # - Functions
    # -- Dealing with CSV Reporting
    def saveDictCSV (dictionary,filename):
    	directory = os.path.dirname(filename)
    	if not os.path.exists(directory):
    		os.makedirs(directory)
    	theFile = open(filename,'wb')
    	w = csv.DictWriter(theFile, dictionary.keys())
    	w.writerow(dictionary)
    	theFile.close()
    
    def saveDictCSVappend (dictionary,filename):
    	directory = os.path.dirname(filename)
    	if not os.path.exists(directory):
    		os.makedirs(directory)
    	theFile = open(filename,'a')
    	w = csv.DictWriter(theFile, dictionary.keys())
    	w.writerow(dictionary)
    	theFile.close()
    
    # -- Glyph bounds extractor
    def extractGlyphBounds(font, glyphList):
    	# - List of glyph widths where NA marks a glyph not found
    	reportValues = [int(font[font.FindGlyph(glyph)].GetBoundingRect().width) if font.FindGlyph(glyph) != -1 else 'NA' for glyph in glyphList]
    
    	# - Report
    	reportKeys = ['Typeface'] + glyphList
    	reportValues = [font.full_name] + reportValues
    
    	reportHeader = dict(zip(reportKeys,reportKeys))
    	reportDict = dict(zip(reportKeys,reportValues))
    
    	if not os.path.exists(fileNameCSV): # Make Header by initial run
    		saveDictCSVappend(reportHeader, fileNameCSV)
    		saveDictCSVappend(reportDict, fileNameCSV)
    	else:
    		saveDictCSVappend(reportDict, fileNameCSV)
    
    # - RUN
    # -- Extract Data from desired fontList
    for fontFile in fontList:
    	fl.Open(fontFile) 					# Open File
    	font = fl.font						# Set current
    	extractGlyphBounds(font, glyphList)	# Extract data
    	fl.Close(0)							# Close current
    
    # - END
    


  • ...Note that although, the CSV may look messy (using dictionaries always ends like this) all the info will land exactly in it's place...


    Surely you should do "dictionary.keys().sort()" or some such, instead plain "dictionary.keys()" in every place it is used?

    My python is a bit rusty, but almost every language's dictionary implementation never return keys in any particular order (that's the whole point of a dictionary - it is indexed by the keys, which is unordered), but in all the object oriented languages, keys() returns an array type which has a sort() method. You can probably do sort(<customcompare delegate>) for some fancy sorting in many languages too.

    C# I think has an ordered dictionary type where keys() returns keys in insertion order.
  • To use Ben's code in FL or Glyphs you need to add (as the first line):
    from robofab.world import CurrentFont
    Yes, that fixed it in both Glyphs and FL, thank you! And many thanks to @Ben Kiel  

    In pure FontLab code the following will work like charm (tested on Windows).
    It also works perfectly on Mac OS 10.9.5! Thank you very much, it's exactly what I needed :) The CSV thingy saves so much time. The sorting is kind of off, but it doesn't matter much. 

    Hin-Tak Leung said:
    What platform are you on?
    I'm on a Mac, 10.9.5. If it's too much trouble to find that code, then nevermind, Vassil's script is great for my needs :) Thanks for looking into it!