Merge pull request #2382 from fonttools/ignore-overlap-errors-option

instancer: add --ignore-overlap-errors option
This commit is contained in:
Cosimo Lupo 2021-08-02 10:34:18 +01:00 committed by GitHub
commit 5cb288f345
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 9 deletions

View File

@ -115,6 +115,7 @@ def _simplify(path: pathops.Path, debugGlyphName: str) -> pathops.Path:
) )
return path return path
except pathops.PathOpsError as e: except pathops.PathOpsError as e:
if log.isEnabledFor(logging.DEBUG):
path.dump() path.dump()
raise RemoveOverlapsError( raise RemoveOverlapsError(
f"Failed to remove overlaps from glyph {debugGlyphName!r}" f"Failed to remove overlaps from glyph {debugGlyphName!r}"
@ -162,6 +163,7 @@ def removeOverlaps(
font: ttFont.TTFont, font: ttFont.TTFont,
glyphNames: Optional[Iterable[str]] = None, glyphNames: Optional[Iterable[str]] = None,
removeHinting: bool = True, removeHinting: bool = True,
ignoreErrors=False,
) -> None: ) -> None:
"""Simplify glyphs in TTFont by merging overlapping contours. """Simplify glyphs in TTFont by merging overlapping contours.
@ -179,6 +181,8 @@ def removeOverlaps(
glyphNames: optional iterable of glyph names (str) to remove overlaps from. glyphNames: optional iterable of glyph names (str) to remove overlaps from.
By default, all glyphs in the font are processed. By default, all glyphs in the font are processed.
removeHinting (bool): set to False to keep hinting for unmodified glyphs. removeHinting (bool): set to False to keep hinting for unmodified glyphs.
ignoreErrors (bool): set to True to ignore errors while removing overlaps,
thus keeping the tricky glyphs unchanged (fonttools/fonttools#2363).
""" """
try: try:
glyfTable = font["glyf"] glyfTable = font["glyf"]
@ -206,10 +210,15 @@ def removeOverlaps(
) )
modified = set() modified = set()
for glyphName in glyphNames: for glyphName in glyphNames:
try:
if removeTTGlyphOverlaps( if removeTTGlyphOverlaps(
glyphName, glyphSet, glyfTable, hmtxTable, removeHinting glyphName, glyphSet, glyfTable, hmtxTable, removeHinting
): ):
modified.add(glyphName) modified.add(glyphName)
except RemoveOverlapsError:
if not ignoreErrors:
raise
log.error("Failed to remove overlaps for '%s'", glyphName)
log.debug("Removed overlaps for %s glyphs:\n%s", len(modified), " ".join(modified)) log.debug("Removed overlaps for %s glyphs:\n%s", len(modified), " ".join(modified))

View File

@ -127,6 +127,7 @@ class OverlapMode(IntEnum):
KEEP_AND_DONT_SET_FLAGS = 0 KEEP_AND_DONT_SET_FLAGS = 0
KEEP_AND_SET_FLAGS = 1 KEEP_AND_SET_FLAGS = 1
REMOVE = 2 REMOVE = 2
REMOVE_AND_IGNORE_ERRORS = 3
def instantiateTupleVariationStore( def instantiateTupleVariationStore(
@ -1185,7 +1186,8 @@ def instantiateVariableFont(
on all glyphs to maximise cross-compatibility of the generated instance. on all glyphs to maximise cross-compatibility of the generated instance.
You can disable this by passing OverlapMode.KEEP_AND_DONT_SET_FLAGS. You can disable this by passing OverlapMode.KEEP_AND_DONT_SET_FLAGS.
If you want to remove the overlaps altogether and merge overlapping If you want to remove the overlaps altogether and merge overlapping
contours and components, you can pass OverlapMode.REMOVE. Note that this contours and components, you can pass OverlapMode.REMOVE (or
REMOVE_AND_IGNORE_ERRORS to not hard-fail on tricky glyphs). Note that this
requires the skia-pathops package (available to pip install). requires the skia-pathops package (available to pip install).
The overlap parameter only has effect when generating full static instances. The overlap parameter only has effect when generating full static instances.
updateFontNames (bool): if True, update the instantiated font's name table using updateFontNames (bool): if True, update the instantiated font's name table using
@ -1244,11 +1246,14 @@ def instantiateVariableFont(
if "glyf" in varfont: if "glyf" in varfont:
if overlap == OverlapMode.KEEP_AND_SET_FLAGS: if overlap == OverlapMode.KEEP_AND_SET_FLAGS:
setMacOverlapFlags(varfont["glyf"]) setMacOverlapFlags(varfont["glyf"])
elif overlap == OverlapMode.REMOVE: elif overlap in (OverlapMode.REMOVE, OverlapMode.REMOVE_AND_IGNORE_ERRORS):
from fontTools.ttLib.removeOverlaps import removeOverlaps from fontTools.ttLib.removeOverlaps import removeOverlaps
log.info("Removing overlaps from glyf table") log.info("Removing overlaps from glyf table")
removeOverlaps(varfont) removeOverlaps(
varfont,
ignoreErrors=(overlap == OverlapMode.REMOVE_AND_IGNORE_ERRORS),
)
varLib.set_default_weight_width_slant( varLib.set_default_weight_width_slant(
varfont, varfont,
@ -1355,6 +1360,12 @@ def parseArgs(args):
help="Merge overlapping contours and components (only applicable " help="Merge overlapping contours and components (only applicable "
"when generating a full instance). Requires skia-pathops", "when generating a full instance). Requires skia-pathops",
) )
parser.add_argument(
"--ignore-overlap-errors",
dest="ignore_overlap_errors",
action="store_true",
help="Don't crash if the remove-overlaps operation fails for some glyphs.",
)
parser.add_argument( parser.add_argument(
"--update-name-table", "--update-name-table",
action="store_true", action="store_true",
@ -1371,6 +1382,9 @@ def parseArgs(args):
options = parser.parse_args(args) options = parser.parse_args(args)
if options.remove_overlaps: if options.remove_overlaps:
if options.ignore_overlap_errors:
options.overlap = OverlapMode.REMOVE_AND_IGNORE_ERRORS
else:
options.overlap = OverlapMode.REMOVE options.overlap = OverlapMode.REMOVE
else: else:
options.overlap = OverlapMode(int(options.overlap)) options.overlap = OverlapMode(int(options.overlap))