Coder Social home page Coder Social logo

fonttools's Introduction

CI Build Status Coverage Status PyPI Join the chat at https://gitter.im/fonttools-dev/Lobby

What is this?

fontTools is a library for manipulating fonts, written in Python. The project includes the TTX tool, that can convert TrueType and OpenType fonts to and from an XML text format, which is also called TTX. It supports TrueType, OpenType, AFM and to an extent Type 1 and some Mac-specific formats. The project has an MIT open-source licence.
Among other things this means you can use it free of charge.

User documentation and developer documentation are available at Read the Docs.

Installation

FontTools requires Python 3.8 or later. We try to follow the same schedule of minimum Python version support as NumPy (see NEP 29).

The package is listed in the Python Package Index (PyPI), so you can install it with pip:

pip install fonttools

If you would like to contribute to its development, you can clone the repository from GitHub, install the package in 'editable' mode and modify the source code in place. We recommend creating a virtual environment, using virtualenv or Python 3 venv module.

# download the source code to 'fonttools' folder
git clone https://github.com/fonttools/fonttools.git
cd fonttools

# create new virtual environment called e.g. 'fonttools-venv', or anything you like
python -m virtualenv fonttools-venv

# source the `activate` shell script to enter the environment (Unix-like); to exit, just type `deactivate`
. fonttools-venv/bin/activate

# to activate the virtual environment in Windows `cmd.exe`, do
fonttools-venv\Scripts\activate.bat

# install in 'editable' mode
pip install -e .

Optional Requirements

The fontTools package currently has no (required) external dependencies besides the modules included in the Python Standard Library. However, a few extra dependencies are required by some of its modules, which are needed to unlock optional features. The fonttools PyPI distribution also supports so-called "extras", i.e. a set of keywords that describe a group of additional dependencies, which can be used when installing via pip, or when specifying a requirement. For example:

pip install fonttools[ufo,lxml,woff,unicode]

This command will install fonttools, as well as the optional dependencies that are required to unlock the extra features named "ufo", etc.

  • Lib/fontTools/misc/etree.py

    The module exports a ElementTree-like API for reading/writing XML files, and allows to use as the backend either the built-in xml.etree module or lxml. The latter is preferred whenever present, as it is generally faster and more secure.

    Extra: lxml

  • Lib/fontTools/ufoLib

    Package for reading and writing UFO source files; it requires:

    • fs: (aka pyfilesystem2) filesystem abstraction layer.
    • enum34: backport for the built-in enum module (only required on Python < 3.4).

    Extra: ufo

  • Lib/fontTools/ttLib/woff2.py

    Module to compress/decompress WOFF 2.0 web fonts; it requires:

    • brotli: Python bindings of the Brotli compression library.

    Extra: woff

  • Lib/fontTools/ttLib/sfnt.py

    To better compress WOFF 1.0 web fonts, the following module can be used instead of the built-in zlib library:

    • zopfli: Python bindings of the Zopfli compression library.

    Extra: woff

  • Lib/fontTools/unicode.py

    To display the Unicode character names when dumping the cmap table with ttx we use the unicodedata module in the Standard Library. The version included in there varies between different Python versions. To use the latest available data, you can install:

    • unicodedata2: unicodedata backport for Python 3.x updated to the latest Unicode version 15.0.

    Extra: unicode

  • Lib/fontTools/varLib/interpolatable.py

    Module for finding wrong contour/component order between different masters. It requires one of the following packages in order to solve the so-called "minimum weight perfect matching problem in bipartite graphs", or the Assignment problem:

    • scipy: the Scientific Library for Python, which internally uses NumPy arrays and hence is very fast;
    • munkres: a pure-Python module that implements the Hungarian or Kuhn-Munkres algorithm.

    To plot the results to a PDF or HTML format, you also need to install:

    • pycairo: Python bindings for the Cairo graphics library. Note that wheels are currently only available for Windows, for other platforms see pycairo's installation instructions.

    Extra: interpolatable

  • Lib/fontTools/varLib/plot.py

    Module for visualizing DesignSpaceDocument and resulting VariationModel.

    Extra: plot

  • Lib/fontTools/misc/symfont.py

    Advanced module for symbolic font statistics analysis; it requires:

    • sympy: the Python library for symbolic mathematics.

    Extra: symfont

  • Lib/fontTools/t1Lib.py

    To get the file creator and type of Macintosh PostScript Type 1 fonts on Python 3 you need to install the following module, as the old MacOS module is no longer included in Mac Python:

    • xattr: Python wrapper for extended filesystem attributes (macOS platform only).

    Extra: type1

  • Lib/fontTools/ttLib/removeOverlaps.py

    Simplify TrueType glyphs by merging overlapping contours and components.

    • skia-pathops: Python bindings for the Skia library's PathOps module, performing boolean operations on paths (union, intersection, etc.).

    Extra: pathops

  • Lib/fontTools/pens/cocoaPen.py and Lib/fontTools/pens/quartzPen.py

    Pens for drawing glyphs with Cocoa NSBezierPath or CGPath require:

    • PyObjC: the bridge between Python and the Objective-C runtime (macOS platform only).
  • Lib/fontTools/pens/qtPen.py

    Pen for drawing glyphs with Qt's QPainterPath, requires:

    • PyQt5: Python bindings for the Qt cross platform UI and application toolkit.
  • Lib/fontTools/pens/reportLabPen.py

    Pen to drawing glyphs as PNG images, requires:

    • reportlab: Python toolkit for generating PDFs and graphics.
  • Lib/fontTools/pens/freetypePen.py

    Pen to drawing glyphs with FreeType as raster images, requires:

    • freetype-py: Python binding for the FreeType library.
  • Lib/fontTools/ttLib/tables/otBase.py

    Use the Harfbuzz library to serialize GPOS/GSUB using hb_repack method, requires:

    • uharfbuzz: Streamlined Cython bindings for the harfbuzz shaping engine

    Extra: repacker

How to make a new release

  1. Update NEWS.rst with all the changes since the last release. Write a changelog entry for each PR, with one or two short sentences summarizing it, as well as links to the PR and relevant issues addressed by the PR. Do not put a new title, the next command will do it for you.
  2. Use semantic versioning to decide whether the new release will be a 'major', 'minor' or 'patch' release. It's usually one of the latter two, depending on whether new backward compatible APIs were added, or simply some bugs were fixed.
  3. Run python setup.py release command from the tip of the main branch. By default this bumps the third or 'patch' digit only, unless you pass --major or --minor to bump respectively the first or second digit. This bumps the package version string, extracts the changes since the latest version from NEWS.rst, and uses that text to create an annotated git tag (or a signed git tag if you pass the --sign option and your git and Github account are configured for signing commits using a GPG key). It also commits an additional version bump which opens the main branch for the subsequent developmental cycle
  4. Push both the tag and commit to the upstream repository, by running the command git push --follow-tags. Note: it may push other local tags as well, be careful.
  5. Let the CI build the wheel and source distribution packages and verify both get uploaded to the Python Package Index (PyPI).
  6. [Optional] Go to fonttools Github Releases page and create a new release, copy-pasting the content of the git tag message. This way, the release notes are nicely formatted as markdown, and users watching the repo will get an email notification. One day we shall automate that too.

Acknowledgements

In alphabetical order:

aschmitz, Olivier Berten, Samyak Bhuta, Erik van Blokland, Petr van Blokland, Jelle Bosma, Sascha Brawer, Tom Byrer, Antonio Cavedoni, Frédéric Coiffier, Vincent Connare, David Corbett, Simon Cozens, Dave Crossland, Simon Daniels, Peter Dekkers, Behdad Esfahbod, Behnam Esfahbod, Hannes Famira, Sam Fishman, Matt Fontaine, Takaaki Fuji, Rob Hagemans, Yannis Haralambous, Greg Hitchcock, Jeremie Hornus, Khaled Hosny, John Hudson, Denis Moyogo Jacquerye, Jack Jansen, Tom Kacvinsky, Jens Kutilek, Antoine Leca, Werner Lemberg, Tal Leming, Peter Lofting, Cosimo Lupo, Olli Meier, Masaya Nakamura, Dave Opstad, Laurence Penney, Roozbeh Pournader, Garret Rieger, Read Roberts, Colin Rofls, Guido van Rossum, Just van Rossum, Andreas Seidel, Georg Seifert, Chris Simpkins, Miguel Sousa, Adam Twardoch, Adrien Tétar, Vitaly Volkov, Paul Wise.

Copyrights

Copyright (c) 1999-2004 Just van Rossum, LettError ([email protected])
See LICENSE for the full license.

Copyright (c) 2000 BeOpen.com. All Rights Reserved.

Copyright (c) 1995-2001 Corporation for National Research Initiatives. All Rights Reserved.

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All Rights Reserved.

Have fun!

fonttools's People

Contributors

adrientetar avatar anthrotype avatar behdad avatar belluzj avatar benkiel avatar brawer avatar chrissimpkins avatar colinmford avatar davelab6 avatar dependabot[bot] avatar dscorbett avatar garretrieger avatar jamesgk avatar jenskutilek avatar justvanrossum avatar khaledhosny avatar letterror avatar m4rc1e avatar madig avatar mashabow avatar mhosken avatar miguelsousa avatar moyogo avatar ollimeier avatar pyup-bot avatar readroberts avatar rsheeter avatar simoncozens avatar takaakifuji avatar typesupply avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fonttools's Issues

Support FeatureParams

Support for FeatureParams seems to be broken (or missing altogether), for example if you decompile and recompile XITS Math and then opening it in FontForge it will complain:

The name parameter of the 'ss01' feature does not contain a valid name id.

And all stylistic set feature names are gone. Similar issue with EB Garamond, but this time with the size feature which gets completely lost.

There is a couple of tickets open for this in the old project: 3 and 4.

NameError: global name 'GlyphCoords' is not defined

On behdad/fonttools git master today:

$ ttx OpenSans-Regular.ttx
Traceback (most recent call last):
  File "/usr/local/bin/ttx", line 6, in <module>
    ttx.main(sys.argv[1:])
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttx.py", line 332, in main
    process(jobs, options)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttx.py", line 317, in process
    action(input, output, options)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttx.py", line 218, in ttCompile
    ttf.importXML(input, quiet=options.quiet)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/__init__.py", line 328, in importXML
    xmlImport.importXML(self, file, progress, quiet)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/xmlImport.py", line 136, in importXML
    p.parse()
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/xmlImport.py", line 25, in parse
    self.parseFile(file)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/xmlImport.py", line 45, in parseFile
    parser.Parse(chunk, 0)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/xmlImport.py", line 109, in endElementHandler
    self.currentTable.fromXML(self.root, self.ttFont)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/tables/_g_l_y_f.py", line 124, in fromXML
    glyph.fromXML(element, ttFont)
  File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/tables/_g_l_y_f.py", line 284, in fromXML
    coordinates = GlyphCoords()
NameError: global name 'GlyphCoords' is not defined
$ cd ~/src/fonttools-behdad;
$ git pull
Already up-to-date.
$ grep -ri GlyphCoords *
Lib/fontTools/ttLib/tables/_g_l_y_f.py:         coordinates = GlyphCoords()
$

[subset] WISH: Better dealing with "Macintosh standard names"

Email from Adam. I haven't studied it yet.

Because of the conflict between the Apple "standard Macintosh glyph names" list and the Adobe "Glyph List for New Fonts", it often happens with tools that one glyph name is (theoretically) "written" into a font but then fontTools interprets it as a different glyph name, which leads to confusion. fontTools uses the strict Apple list while other tools use the Adobe list. I've documented it in an e-mail to the OpenType list, which I'm including below. It mostly happens with "CR" vs "nonmarkingreturn" and with "NULL" vs. ".null". So I "think" I put "CR" into the font, and use "CR" in my subset definition, but fontTools interprets it as "nonmarkingreturn".

This is such a tedious thing that it might require a "hack", i.e. treating JUST the mismatching glyphs as synonyms, i.e. the parser for the escapement convention should have a few heuristics to translate "CR" into "nonmarkingreturn" if "CR" is not found in the font but "nonmarkingreturn" is. This affects only just 8 or 9 glyphs involved.

Such "translation" of a glyph name might also issue a warning.

Best,
Adam

There are several aspects for this:

  1. Adobe has created AGL (the Adobe Glyph List) and AGLFN (the Adobe Glyph List For New fonts). These lists [1] are accompanied by an Adobe spec [3] which describes how "good" glyph names should be created. Their primary purpose was to create support text extraction out of PDF documents if Unicode information is lost (i.e. if the font in the PDF has been embedded as Type 1 or raw CFF, without "cmap" or /ToUnicode PDF resource)
  2. Apple has created their list [5] as part of the TrueType spec. If the Apple names are used, then the explicit glyph name is not stored. So it's a sort of "compressed" glyph name storage. They are used in "post" table versions 1.0 and 2.0.
  3. In the OpenType spec, Microsoft references the WGL4 character set from the "post" table spec [4], which, as it seems, conflicts with the Apple list. Microsoft also uses slightly different names in the OT spec recommendations [2].

It's details, but it's confusing. Some font tools use the Apple list, others use the AGLFN/AGL lists, yet others use some hybrid lists which are custom-created and have been created this way as a compromise (notably FontLab with its standard.nam).

I'm discussing the differences between the Apple, Adobe, Microsoft and FontLab names below. Specifically, there are 8 or 9 glyphs involved.

At FontLab, we'd be interested in a FINAL community / normative decision as to how to best name these glyphs in both TT and CFF-flavored fonts. It really has been bugging many font developers for a long time now. Ideally, we should decide, and then Adobe, Apple, Microsoft, and tool makers such as FontLab, should adjust their tables and specs accordingly.

  1. Big problems:
  • .null (U+0000)

Is not in AGL on AGLFN [1], but it is in the Apple list [5] and in the MS recommendations [2]. The older Adobe spec recommended that only ".notdef" can start with a "." but the current Adobe spec [3] no longer says that. Some font vendors have been using "NULL" or "NUL" instead of ".null". Others have used "uni0000" as it resolves to U+0000 per the Adobe spec. Currently, at FontLab, we use "NULL" by default.

  • nonmarkingreturn (U+000D)

Is not in AGL or AGLFN, but it is in the Apple list. But "controlCR" is in AGL. Some font vendors have used "CR". Others have used "uni000D" because it resolves per Adobe spec. Currently, at FontLab, we use "CR" by default.

  • nonbreakingspace (U+00A0)

Is not in AGLFN but is in AGL and in the Apple list. Some font vendors have used "uni00A0". Currently, at FontLab, we use "uni00A0" by default.

At FontLab, we'd be interested in a FINAL community decision as to how to best name these glyphs in both TT and CFF-flavored fonts.

  1. Mid-sized problems
  • onesuperior (U+00B9), twosuperior (U+00B2), threesuperior (U+00B3)

Are not in AGLFN but are in AGL and in the Apple list. I haven't seen fonts which would use "uniXXXX" for those. Currently, at FontLab, we use "onesuperior", "twosuperior", "threesuperior" by default.

  • fi (U+FB01), fl (U+FB02)

Are not in AGLFN but are in AGL and in the Apple list. Some font vendors use "uniFB01", "uniFB02" for those if they provide separate glyph copies for use in OpenType Layout. Others who provide unified glyphs use "f_i" and "f_l". Currently, at FontLab, we use "fi", "fl" by default.

  • middot vs periodcentered, overscore vs macron -- same problem
  1. Minor problem
  • apple (U+F8FF)

Is not in AGLFN but is in AGL and in the Apple list. Since it's PUA, it's not so important. Also, since it's an Apple trademark, many vendors have used "uniF8FF". At FontLab, we use "uniF8FF" by default.

At FontLab, we think it's best to stick to "uniF8FF" for this.

[1] http://sourceforge.net/projects/aglfn.adobe/
[2] http://www.microsoft.com/typography/otspec/recom.htm
[3] http://sourceforge.net/adobe/aglfn/wiki/AGL%20Specification/
[4] https://www.microsoft.com/typography/otspec/post.htm
[5] Apple list (part of fontTools)

[subset] Support removing glyphs from requested set

As Adam requested:

If possible, please implement a special * glyph identifier which means „entire glyph set”. It would be useful if one wanted to do the non-subsetting optimizations. And, it would be particularly useful when combined with a - prefix for glyph identifiers.

For example, I’d like to run pyftsubset as follows:

pyftsubset font.ttf * -A -B -U+E000

Then, the subsetter would remove the glyphs A, B and the character U+E000 but would retain all other glyphs.

The "*" part is implemented already.

Tool to split/merge TTC

As requested by Adam. Would be useful. Possibly as a separate tool as well as with support in ttx.

Write out 'name' table entries as UTF-8 text in XML

Right now name table entries are hacked into the XML. Given the entry's platform/encoding etc we know the text encoding. As such, we should try to decode it to Unicode and write out the Unicode to XML. Add a "raw" attribute to it, so we can 1. accept the current behavior if the attribute is not present, and 2. Still roundtrip if the name entry fails to decode under its encoding.

[subset] WISH: Include features not specced via --layout-features but covered by final glyphset

Email from Adam. Haven't studied it in detail yet.

In addition to pyftsubset, there is another very able font subsetter, "ttfsubset", written by Marin Hosken from SIL, in Perl, as part of his (very powerful, actually, Font::TTF package):
http://scripts.sil.org/fontutils

The commandline params are here:
http://search.cpan.org/~mhosken/Font-TTF-Scripts/scripts/ttfsubset

It only works on TTF-based fonts, and in some more complex cases generates problematic GPOS stuff (with references to non-existent GIDs and stuff). But overall, so far, it's been the best thing available. Its execution time is about 2x of yours.

I'm attaching a test archive. orig.ttf is the original EB Garamond, and then there are two subset glyph lists:

  • subset.txt is the one which I used originally to subset using pyftsubset and ttfsubset
  • subset-alts.txt which is the list of glyphs made in a special way, I'll explain in a second.

So I ran sub-ttx.sh to produce sub-ttx.ttf. Since sub-ttx.sh includes --layout-features=liga,kern,mark,mkmk,ccmp,calt,dlig,lnum,onum,pnum,tnum,case , a number of additional glyphs were included in the resulting font, which is great. So in a way, in pyftsubset, we have a "mandatory" glyph list specified by the user directly, and through the --layout-features option which is a sort of a "greedy" operator, we have a list of "optional" glyphs which are included because they are GSUB results of the mandatory glyphs and the specified features.

So I saved the glyph list of sub-ttx.ttf as subset-alts.txt.

Then I ran sub-pl.sh (which runs ttfsubset with subset.txt) to produce sub-pl.ttf, and I ran sub-pl-alts.sh (which runs ttfsubset with subset-alts.txt) to produce sub-pl-alts.ttf.

And then finally, I also ran sub-ttx-alts.sh, which also uses the glyphs from subset-alts.txt.

So what we can see is that the tools follow two different strategies when it comes to OT features:

  • pyftsubset uses the mandatory glyph list and the feature list to extend the actual glyph list to be included, but keeps the features as they were specified, and throws out the ones that aren't specified explicitly
  • ttfsubset uses the mandatory glyph list, period -- but it actually tries to keep a subset of the features which "fit" into the declared glyph set.

These approaches are orthogonal. On one hand, the pyftsubset "greedy" glyph set handling is great, but then it's a pity that it actually leaves out some features that could still fit in. For example, even though I did specify "mark" and "mkmk" in the list of features to keep, it didn't keep them because no marks that are used in "mark" and "mkmk" were explicitly enumerated in the glyph list. But since some of the marks are used as component glyphs of the base glyphs, there could be actually a tiny "mark" or "mkmk" feature left.

On the other hand, ttfsubset does not automatically extend the glyph set, so it's strict -- but then, it detects which features could be kept for that given, defined glyph set. And it actually leaves in "mkmk" and "mark", but also "subs", "dnom", "ordn" and a few others.

Since pyftsubset produces a larger than specified glyphset (the -alts set), I could run it again with the resulting glyphset. Then, it did catch "mark" and "mkmk", because the glyphs which were previously mere components have now been listed in the "mandatory" set.

But then again, with more glyphs (the -alts set), ttfsubset was able to leave in even more features.

I think it would be tremendous if pyftsubset had an option "--extend-features". If specifed, it would behave more like ttfsubset, i.e. it would use the glyphs specified as mandatory glyphs along with the features specified in --layout-features to extend the glyph set, but then after extending the glyph set it would also try to keep other features if they fit into the extended glyph set.

That would be perfect: you define the glyphs you MUST have and the features you MUST have, and have the ability to arrive at the font that has all that but also has the most complete subset of the original features, including the ones you didn't explicitly specify via --layout-features.

Without "--extend-features", pyftsubset would behave as it does now.

Skia.ttf from Mac OS X 10.9 breaks TTX

I didn’t try older versions of the font, but the version shipped with 10.9 break TTX:

Dumping 'prep' table...
Traceback (most recent call last):
  File "/somewhere/bin/ttx", line 8, in <module>
    execfile(__file__)
  File "/somewhere/fonttools/Tools/ttx", line 6, in <module>
    ttx.main(sys.argv[1:])
  File "/somewhere/fonttools/Lib/fontTools/ttx.py", line 332, in main
    process(jobs, options)
  File "/somewhere/fonttools/Lib/fontTools/ttx.py", line 317, in process
    action(input, output, options)
  File "/somewhere/fonttools/Lib/fontTools/ttx.py", line 208, in ttDump 
    bitmapGlyphDataFormat=options.bitmapGlyphDataFormat)
  File "/somewhere/fonttools/Lib/fontTools/ttLib/__init__.py", line 275, in saveXML
    self._tableToXML(tableWriter, tag, progress, quiet)
  File "/somewhere/fonttools/Lib/fontTools/ttLib/__init__.py", line 312, in _tableToXML
    table.toXML(writer, self)
  File "/somewhere/fonttools/Lib/fontTools/ttLib/tables/_f_p_g_m.py", line 16, in toXML
    self.program.toXML(writer, ttFont)
  File "/somewhere/fonttools/Lib/fontTools/ttLib/tables/ttProgram.py", line 228, in toXML
    assembly = self.getAssembly()
  File "/somewhere/fonttools/Lib/fontTools/ttLib/tables/ttProgram.py", line 223, in getAssembly
    self._disassemble()
  File "/somewhere/fonttools/Lib/fontTools/ttLib/tables/ttProgram.py", line 356, in _disassemble
    raise tt_instructions_error, "illegal opcode: 0x%.2x" % op
fontTools.ttLib.tables.ttProgram.tt_instructions_error: TT instructions error: 'illegal opcode: 0x91'

Make XML output less noisy re optimizations

If you have a ttf produced by a tool other than fonttools, currently if you do ttf->xml->ttf->xml the two XML files typically differ in two general categories:

  • GSUB/GPOS/GDEF Coverage/ClassDef formats. FontTools chooses whatever format (1 or 2) that is more compact. The actual contents of the table are equivalent and the XML contents are also the same. It's just a format number making it to the XML, which is then ignored during compile(). It's a useful thing when compiling bogus software / fonts, but not otherwise useful and representative of any inherent information about the font,
  • TrueType hinting push instructions: If the font originally had, eg, PUSHW instructions but the numbers being pushed are all small, fonttools uses a PUSHB instead of PUSHW. Similarly, if the number of items pushed is < 8, fonttools uses PUSHB/PUSHW instead of NPUSHB/NPUSHW. In other words, fonttools changes the provided bytecode as it sees fit,

What I'm suggesting is to hide these differences from XML. Ie. don't write the Coverage/ClassDef format, and write all of PUSHW/PUSHB/NPUSHW/NPUSHB instructions as a new generic PUSH instruction. Possibly remove the auto-choose policy to use exactly the instruction provided if it's not the new generic PUSH. Possibly same about the Coverage format.

In a similar vein, in the future we will implement generic cmap subtables where choose the best subtable format...

Feedback? Do we care about adding an option to ttx to disable this? I have a hard time imagining a real use for it.

Subsetting CFFs without subroutines

When testing the subsetter script, I came across a very complex font that apparently doesn’t use subroutines. The subsetter chokes on that ... I think the script has to check if there are any subroutines:

--- subset.py   2013-09-03 12:08:32.000000000 +0200
+++ subset.py   2013-09-03 12:47:09.000000000 +0200
@@ -1404,7 +1404,8 @@
     if hasattr(font, 'FDSelect'):
       all_subrs.extend(fd.Private.Subrs for fd in font.FDArray if hasattr(fd.Private, 'Subrs'))
     else:
-      all_subrs.append(font.Private.Subrs)
+      if hasattr(font.Private, 'Subrs'):
+        all_subrs.append(font.Private.Subrs)
     # Prepare
     for subrs in all_subrs:
       if not subrs: continue

Automatically add/remove Extension subtables

Extension subtable mechanism is a way to work around the 64k limit of Offset types. So, user shouldn't worry about it and we should just automatically introduce them when compiling GSUB/GPOS tables.

POST table issue?

THSarabunNew.zip can be downloaded from around the web - https://www.google.co.uk/search?q=THSarabunNew.zip

$ ttx *f;
Dumping "THSarabunNew Bold.ttf" to "THSarabunNew Bold.ttx"...
Dumping 'GlyphOrder' table...
Dumping 'head' table...
Dumping 'hhea' table...
Dumping 'maxp' table...
Dumping 'OS/2' table...
Dumping 'hmtx' table...
Dumping 'LTSH' table...
Dumping 'VDMX' table...
Dumping 'hdmx' table...
Dumping 'cmap' table...
Dumping 'fpgm' table...
Dumping 'prep' table...
Dumping 'cvt ' table...
Dumping 'loca' table...
Dumping 'glyf' table...
Dumping 'kern' table...
Dumping 'name' table...
Dumping 'post' table...
Dumping 'gasp' table...
*** Warning: offset is not 0, yet suspiciously low (2). table: MarkAttachClassDef
Dumping 'GDEF' table...
Dumping 'GPOS' table...
Dumping 'GSUB' table...
Dumping 'feat' table...
Dumping 'morx' table...
Dumping 'DSIG' table...
Dumping "THSarabunNew BoldItalic.ttf" to "THSarabunNew BoldItalic.ttx"...
Dumping 'GlyphOrder' table...
Dumping 'head' table...
Dumping 'hhea' table...
Dumping 'maxp' table...
Dumping 'OS/2' table...
Dumping 'hmtx' table...
Dumping 'LTSH' table...
Dumping 'VDMX' table...
Dumping 'hdmx' table...
Dumping 'cmap' table...
Dumping 'fpgm' table...
Dumping 'prep' table...
Dumping 'cvt ' table...
Dumping 'loca' table...
Dumping 'glyf' table...
Dumping 'kern' table...
Dumping 'name' table...
Dumping 'post' table...
Dumping 'gasp' table...
Dumping 'PCLT' table...
*** Warning: offset is not 0, yet suspiciously low (2). table: MarkAttachClassDef
Dumping 'GDEF' table...
Dumping 'GPOS' table...
Dumping 'GSUB' table...
Dumping 'feat' table...
Dumping 'morx' table...
Dumping 'DSIG' table...
Dumping "THSarabunNew Italic.ttf" to "THSarabunNew Italic.ttx"...
Dumping 'GlyphOrder' table...
Dumping 'head' table...
Dumping 'hhea' table...
Dumping 'maxp' table...
Dumping 'OS/2' table...
Dumping 'hmtx' table...
Dumping 'LTSH' table...
Dumping 'VDMX' table...
Dumping 'hdmx' table...
Dumping 'cmap' table...
Dumping 'fpgm' table...
Dumping 'prep' table...
Dumping 'cvt ' table...
Dumping 'loca' table...
Dumping 'glyf' table...
Dumping 'kern' table...
Dumping 'name' table...
Dumping 'post' table...
Dumping 'gasp' table...
Dumping 'PCLT' table...
*** Warning: offset is not 0, yet suspiciously low (2). table: MarkAttachClassDef
Dumping 'GDEF' table...
Dumping 'GPOS' table...
Dumping 'GSUB' table...
Dumping 'feat' table...
Dumping 'morx' table...
Dumping 'DSIG' table...
Dumping "THSarabunNew.ttf" to "THSarabunNew.ttx"...
Dumping 'GlyphOrder' table...
Dumping 'head' table...
Dumping 'hhea' table...
Dumping 'maxp' table...
Dumping 'OS/2' table...
Dumping 'hmtx' table...
Dumping 'LTSH' table...
Dumping 'VDMX' table...
Dumping 'hdmx' table...
Dumping 'cmap' table...
Dumping 'fpgm' table...
Dumping 'prep' table...
Dumping 'cvt ' table...
Dumping 'loca' table...
Dumping 'glyf' table...
Dumping 'kern' table...
Dumping 'name' table...
Dumping 'post' table...
Dumping 'gasp' table...
*** Warning: offset is not 0, yet suspiciously low (2). table: MarkAttachClassDef
Dumping 'GDEF' table...
Dumping 'GPOS' table...
Dumping 'GSUB' table...
Dumping 'feat' table...
Dumping 'morx' table...
Dumping 'DSIG' table...
$ rm *f;
$ ttx *x;
$ rm *x;

Then Mac OS X refuses to install them:

screen shot 2013-12-08 at 16 20 51

[subset] BUG: pyftsubset fails with both --symbol-cmap --legacy-cmap

From Adam:

when I run the attached shell script with the attached font, I get the following traceback.

It's due to the fact that I include both --symbol-cmap --legacy-cmap options in the call. If I only include one, or none, it works.

A.

Traceback (most recent call last):
File "/usr/local/bin/pyftsubset", line 6, in
subset.main(sys.argv[1:])
File "/Library/Python/2.7/site-packages/FontTools/fontTools/subset.py", line 2082, in main
save_font (font, outfile, options)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/subset.py", line 2012, in save_font
font.save(outfile, reorderTables=options.canonical_order)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 206, in save
self._writeTable(tag, writer, done)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 605, in _writeTable
tabledata = self.getTableData(tag)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 617, in getTableData
return self.tables[tag].compile(self)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/tables/_c_m_a_p.py", line 66, in compile
chunk = table.compile(ttFont)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/tables/_c_m_a_p.py", line 873, in compile
assert codes == range(codes[0], codes[0] + lenCodes)
AssertionError

seguiemj's glyf table

When I roundtrip seguiemj.ttf through ttx, the glyf table size gets bigger. I can't think of any case that this should be the case. Figure out.

cmap sorting broken?

With this commit 96b321c we noticed that some fonts wouldn't pass through the OT sanitizer, apparently because the cmap subtables are sorted incorrectly.

It's hard to reproduce, because the resulting sort order seems to differ when the font is generated repeatedly.

[subset] WISH: Support glyphtext for defining subsets

From Adam:

Currently, pyftsubset allows to specify a text string with the --text option and a list of space-separated glyph names as direct arguments.

The Perl ttfsubset tool written by Martin Hosken (SIL) allows to also specify an external text file where the subset definition is stored. That's very handy.

But I'd like to propose to go a slightly different route:

In FontLab apps, we're using what I call "glyphtext", which is a way to provide a text file or string which uses normal UTF-8 characters to refer to glyphs which have a Unicode codepoint assign, but provides several escapement methods to refer glyphs as well:

a) Escaped glyphname: /nnnn (e.g. /adieresis or /a.smcp), i.e. the slash followed by the glyphname.

b) Escaped CID*: /DDD (e.g. /123 or /5436), i.e. the slash followed by a decimal number corresponding to the CID (character ID). This is supported in CID-keyed fonts only.

c) Escaped glyph ID*: \gDDD (e.g. \g123 or \g0), i.e. the backslash followed by the letter g and followed by a decimal number representing the GID (the SFNT glyph ID).

d) Escaped Unicode codepoint: \XXXX or \uXXXX (e.g. \20ac or \u20AC), i.e. the backlash followed by an optional letter u and followed by the hexadecimal Unicode codepoint — for glyphs that have a Unicode codepoint assigned. XXXX can be 4 or 5 hexadecimal digits; XXXX is case-insensitive.

e) Unescaped character: a single Unicode text character (e.g. A, Ä, Ą, Я) — for glyphs that have a Unicode codepoint assigned. This is the preferred method for glyphs that have a Unicode codepoint assigned.

f) To input the actual slash text character /, the user can enter // (i.e. two slashes). Those two slashes are treated like one unescaped character. To input the actual backslash text character , the user can enter \ (i.e. two backslashes). Those two backslashes are treated like one unescaped character.

*) These are currently not supported by FontLab apps but will be supported in future.

Each glyph in the glyph string can be represented using any character escaping convention method (discussed above). When an an escaped Unicode codepoint or an escaped glyphname is followed by an unescaped text character, the unescaped text character must be separated by a space, which does not count as a text character. Any space between two unescaped characters or between two escaped items is treated as a text character.

Examples
A/Aacute V means a sequence of three glyphs: A, Aacute, V
/A/Aacute/V means the same
A V means s a sequence of three glyphs: A, space, V
/Aacute /V means a sequence of three glyphs: Aacute, space, V

To implement this method, we'd need a fontTools parser module for such files which would take the glyphtext in and produce a list of glyph references out. Glyphtext (aka "FontLab text escapement") is also used by other applications including RoboFont.

So my proposal would be that the user could specify:
--text=%text string%
--text--file=%path to text file%
--glyphtext=%glyphtext string%
--glyphtext-file=%path to glyphtext file%

At FontLab, we're committed to documenting, supporting and publicizing glyphtext. (There will be an official spec published somewhere soon. But the above description pretty much IS the official spec :) ).

[subset] WISH: Ignore glyphs missing from font but present in the glyph names list

Email from Adam.

Currently, pyftsubset throws an exception and fails if list of glyph names to be included in the subset a glyph name is found which is not present in the font. An option --ignore-missing (or --ignore-warnings or something) could be added which would allow graceful continuation.

The current way of working is very slow because it requires the user to figure out each time which glyphs are actually in a font. If it allowed non-existing glyphs to be specified, people could use "standardized lists" for subsets.

[subset] Aggressive vs. conservative OTL feature code removal

From Adam:

I'd like to elaborate on what I wrote in the
https://groups.google.com/forum/#!topic/fonttools/lCwa9N1NEIY
thread.

There is a bit of "chicken and egg" interaction between the specified glyphs and specified features.

Currently the pyftsubset tool does the following:
a) take the specified glyph list
b) take the specified OT feature list
c) form the target glyph list: expand the specified glyph list by adding to the specified glyph list the necessary component glyphs, and the GSUB variants required by the specified OT feature list
d) form the target OT feature list as a direct copy of the specified OT feature list
e) remove all glyphs not in the target glyph list
f) remove all features not in the target OT feature list

As I wrote some time ago, other subsetters (such as SIL Martin Hosken's ttfsubset, part of the Font::TTF Perl package) is more forgiving in terms of what OT Layout stuff to remove. ttfsubset will keep all feature code which is covered by the target glyph list while your subsetter will remove a lot.

More specifically, Martin Hosken's ttfsubset has a different step (d). While pyftsubset uses the specified OT feature list as the target feature list, ttfsubset will construct the target OT feature list by intersecting the original OT feature list with the target glyph list.

In other words:

  • Behdad's pyftsubset performs "aggressive feature removal"
  • Martin Hosken's ttfsubset performs "conservative feature removal"

In a revised implementation of pyftsubset, step (d) could be different (perhaps only when an option such as --preserve-other-features is specified):

d) form the target OT feature list: expand the specified feature list by adding to the specified OT feature list those rules, lookups and features which are covered by the target glyph set

This means that right now, in pyftsubset we have a "must" glyph list and a "must" feature list (specified by the user) PLUS a "may" glyph list (result from the expansion). What I'm requesting is that we have a must glyph list, a must feature list, a may glyph list AND a may feature list.

EXAMPLE 1

Consider a font where I have the glyphs: /A/B/C/D/a/b/c/d/a.smcp/b.smcp/c.smcp/d.smcp and I have the following feature definitions (using FEA syntax):

feature smcp {
sub [a b c d] by [a.smcp b.smcp c.smcp d.smcp];
} smcp;
feature c2sc {
sub [A B C D] by [a.smcp b.smcp c.smcp d.smcp];
} c2sc;

When I run pyftsubset and specify the glyphs to keep: /A/B/a/b/a.smcp/b.smcp (or just /A/B/a/b), and I specify the feature to keep "smcp", then I'll get a font which will have the glyphs: /A/B/a/b/a.smcp/b.smcp but will only have the feature definition:

feature smcp {
sub [a b] by [a.smcp b.smcp];
} smcp;

while the "c2sc" feature will be dropped completely.

Martin Hosken's ttfsubset is smarter. It won't do the automatic expansion of the specified glyph list, so I have to explicitly tell it to keep the glyphs: /A/B/a/b/a.smcp/b.smcp, but after the subsetting, I'll get the same glyph set as from pyftsubset (/A/B/a/b/a.smcp/b.smcp), but I'll get the feature definitions:

feature smcp {
sub [a b] by [a.smcp b.smcp];
} smcp;
feature c2sc {
sub [A B] by [a.smcp b.smcp];
} c2sc;

In other words, since the target glyph list does have all glyphs necessary to form a sensible subset of the "c2sc" feature, Martin Hosken's ttfsubset will retain a subsetted variant of the "c2sc" feature, while pyftsubset will drop "c2sc" completely because I didn't specify it explicitly.

EXAMPLE 2

Let's say I have a font that defines features such as "onum" and "pnum" which replace default figures with the appropriate variants, and it also has "lnum" and "tnum" that do exactly the reverse. In pyftsubset, if I specify to include the features "onum" and "pnum", then only those will be included, and "lnum" and "tnum" will be removed. In Martin's ttfsubset, all four features will be retained.

EXAMPLE 3

Let's say I have the glyph set: /a/b/a.ss01/b.ss01/a.ss02/b.ss02 and I have the feature code:

feature ss01 {
sub [a b] by [a.ss01 b.ss01];
} ss01;
feature ss02 {
sub [a b] by [a.ss02 b.ss02];
} ss02;
feature salt {
sub a from [a.ss01 a.ss02];
sub b from [b.ss01 b.ss02];
} salt;

With pyftsubset, if I want to keep the glyphs /a/b/a.ss01/b.ss01 and the "ss01" feature, I'll only get this:
feature ss01 {
sub [a b] by [a.ss01 b.ss01];
} ss01;

In Martin's ttfsubset, if I specify to keep the glyphs: /a/b/a.ss01/b.ss01, I'll get this:
feature ss01 {
sub [a b] by [a.ss01 b.ss01];
} ss01;
feature salt {
sub a from [a.ss01];
sub b from [b.ss01];
} salt;

Mind you, with pyftsubset, it's virtually impossible to get the (useful) result that ttfsubset produces, because, given the original character set, if I tell pyftsubset to keep the glyphs /a/b and to keep "ss01" and "salt" features, I'll get the original glyph set (including /a.ss02/b.ss02, which I actually don't want).

So Martin's ttfsubset will go beyond just following the specified features, it'll also retain feature code which is not explicitly specified by the user but IS covered by the target glyph set. In other words, ttfsubset operates more "synergetically". I hope you get the idea :)

Such "synergetic" operation would make sense in pyftsubset: if I tell pyftsubset that I want certain glyphs AND certain features, it should give me those glyphs and features but might ALSO give me other features which are covered by the glyph set I'm getting anyway. The thing is, if I also ask for those other features, then pyftsubset will keep expanding the requested glyph list "ad infinitum", so the subset will make less and less sense.

So my question to Behdad is: do you plan/consider to implement something like this, i.e. switch from "aggressive" to "conservative" feature removal? Or does it conflict with your implementation goals/principles for pyftsubset?

Followup:

I think --layout-features='*' should do what you are asking for. Can you test?

Unfortunately, it does not do what I'm asking for. I'll send you an example.

He then sent me the font files that I should have in my inbox.

Python 3 support

I started working on Python 2 and 3 support.
The big chunk of bytes/str/unicode difference is stil todo for it to actually working in Python 3.

Append rather than replace .ttx file extension

ttx replaces the file extensions for .otf and .ttf fonts with .ttx

If you have a directory which contains fonts in pairs (${font}.otf and ${font}.ttf) then ttx'ing all the fonts with ttx *tf will result in ${font}.ttx and ${font}#1.ttx.

However, the -o option will produce .otf.ttx and .ttf.ttx, when run as

$  for x in *tf; do ttx -o "$x.ttx" "$x"; done

Perhaps this could become the default behavior?

[ttx] Use ttx file modification time for font "modified" timestamp

I like to add a mode to ttx, such that when converting a ttx file to a font,
the timestamp of the the ttx file be used as the "modified" field in the font
head table. Currently the "current time" is used.

With that mode, compiling the same ttx file without modifying it, will always
result in the same ttf file. That's useful at least for testing.

Not sure whether this should be default. Asked people on the list for their preference.

Running ttx on TTX files hangs (OSX 10.8.4)

Running ttx on TTX files hangs (OSX 10.8.4)

$ ttx ~/googlefontdirectory/apache/opensans/OpenSans-Regular.ttx
Compiling "/Users/dcrossland/googlefontdirectory/apache/opensans/OpenSans-Regular.ttx" to "/Users/dcrossland/googlefontdirectory/apache/opensans/OpenSans-Regular#3.ttf"...
Parsing 'GlyphOrder' table...
Parsing 'head' table...
Parsing 'hhea' table...
Parsing 'maxp' table...
Parsing 'OS/2' table...
Parsing 'hmtx' table...
Parsing 'cmap' table...
Parsing 'fpgm' table...
Parsing 'prep' table...
Parsing 'cvt ' table...
Parsing 'loca' table...
Parsing 'glyf' table...
Parsing 'kern' table...
Parsing 'name' table...
Parsing 'post' table...
Parsing 'gasp' table...
Parsing 'GDEF' table...
Parsing 'GPOS' table...
Parsing 'GSUB' table...
Parsing 'DSIG' table...
^C^C^C^C
^Z
[1]+  Stopped                 ttx ~/googlefontdirectory/ofl/cantarell/Cantarell-Regular.ttx
$ kill %
[1]+  Stopped                 ttx ~/googlefontdirectory/ofl/cantarell/Cantarell-Regular.ttx
$ fg
-bash: fg: job has terminated
[1]+  Terminated: 15          ttx ~/googlefontdirectory/ofl/cantarell/Cantarell-Regular.ttx
$
$ ttx ~/googlefontdirectory/ofl/cantarell/Cantarell-Regular.ttx
Compiling "/Users/dcrossland/googlefontdirectory/ofl/cantarell/Cantarell-Regular.ttx" to "/Users/dcrossland/googlefontdirectory/ofl/cantarell/Cantarell-Regular#1.ttf"...
Parsing 'GlyphOrder' table...
Parsing 'head' table...
Parsing 'hhea' table...
Parsing 'maxp' table...
Parsing 'OS/2' table...
Parsing 'hmtx' table...
Parsing 'cmap' table...
Parsing 'cvt ' table...
Parsing 'loca' table...
Parsing 'glyf' table...
Parsing 'name' table...
Parsing 'post' table...
Parsing 'gasp' table...
Parsing 'FFTM' table...

NameError: global name 'rec' is not defined

$pyftsubset amiri-regular.ttf --text="زَوُنالعربيةܐܪܡܝܐمصرىآذربايجانجاآذربايجانجابلوچی مکرانیبختياريکوردیفارسیگیلکیهَوُسَکھوارقازاقشا (تٴوتە)کٲشُرکٲشُركورديمازِرونیپنجابیپښتوسنڌيئۇيغۇرچە"
Traceback (most recent call last):
File "/usr/local/bin/pyftsubset", line 6, in
subset.main(sys.argv[1:])
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 1936, in main
subsetter.subset(font)
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 1788, in subset
self._prune_post_subset(font)
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 1775, in _prune_post_subset
retain = table.prune_post_subset(self.options)
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 1049, in prune_post_subset
self.table.LookupList.prune_post_subset(options);
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 875, in prune_post_subset
if l.prune_post_subset(options): ret = True
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 840, in prune_post_subset
if st.prune_post_subset(options): ret = True
File "/usr/local/lib/python2.7/dist-packages/FontTools/fontTools/subset.py", line 406, in prune_post_subset
for m in rec.Mark2Anchor:
NameError: global name 'rec' is not defined

doctests

Right now some files (mostly in misc package) have doctest's run in main. That doesn't work anymore because of non-relative imports. Figure that out. Also, add a main driver to add all Python files' doctests, and start adding tests...

AGL up to date?

Chatting to Akiem from Underware at ATypI, he wondered if the Adobe Glyph List names used by ttx are up to date?

[REGRESSION] _h_m_t_x.py", line 60, in compile metrics = sum(metrics,[]) TypeError: can only concatenate list (not "tuple") to list

Hello Behdad,

I have the following setup:

Mac OS X 10.9 with Python 2.7.5

  1. RoboFab installed from:
    https://github.com/robofab-developers/robofab
  2. ufo2fdk installed from:
    https://github.com/typesupply/ufo2fdk
  3. udo2otf installed from:
    https://pypi.python.org/pypi/ufo2otf/0.2.2
  4. Adobe FDK for OpenType from:
    http://www.adobe.com/devnet/opentype/afdko.html

With the official fontTools installed from SF git:
http://sourceforge.net/p/fonttools/code/ci/master/tree/
calling
$ ufo2otf --afdko infont.ufo
works fine and results in infont.otf

However, with Behdad's fork from Github:
https://github.com/behdad/fonttools
I get the following error:

Traceback (most recent call last):
File "/usr/local/bin/ufo2otf", line 59, in
console()
File "/usr/local/bin/ufo2otf", line 56, in console
c.compile()
File "/Library/Python/2.7/site-packages/ufo2otf/compilers.py", line 166, in afdko
compiler.compile(font, outfile, releaseMode=True)
File "/Library/Python/2.7/site-packages/ufo2fdk/init.py", line 86, in compile
partsCompiler.compile()
File "/Library/Python/2.7/site-packages/ufo2fdk/makeotfParts.py", line 64, in compile
self.setupFile_outlineSource(self.paths["outlineSource"])
File "/Library/Python/2.7/site-packages/ufo2fdk/makeotfParts.py", line 79, in setupFile_outlineSource
c.compile()
File "/Library/Python/2.7/site-packages/ufo2fdk/outlineOTF.py", line 80, in compile
self.otf.save(self.path)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 206, in save
self._writeTable(tag, writer, done)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 602, in _writeTable
self._writeTable(masterTable, writer, done)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 605, in _writeTable
tabledata = self.getTableData(tag)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/init.py", line 617, in getTableData
return self.tables[tag].compile(self)
File "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/tables/_h_m_t_x.py", line 60, in compile
metrics = sum(metrics,[])
TypeError: can only concatenate list (not "tuple") to list

Best,
Adam

[ttx] Control chars in xml

Currently, we write out control chars to XML. That's invalid XML. Need to escape those. Can be in a feature tag, or name table, or CFF, etc. Test for example with Salsa-Regular.otf from googlefontdirectory.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.