From b7f4e9b83e1794b99c8fa8faf59a04ca1d8007f8 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Thu, 25 May 2023 13:42:29 +0100 Subject: [PATCH] move dropImpliedOnCurvePoints function to glyf table module so it can be used by client code on multiple glyf Glyph objects regardles of TTGlyphPen --- Lib/fontTools/pens/ttGlyphPen.py | 56 +------------------------ Lib/fontTools/ttLib/tables/_g_l_y_f.py | 57 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/Lib/fontTools/pens/ttGlyphPen.py b/Lib/fontTools/pens/ttGlyphPen.py index c1590e651..9db320dc3 100644 --- a/Lib/fontTools/pens/ttGlyphPen.py +++ b/Lib/fontTools/pens/ttGlyphPen.py @@ -11,65 +11,13 @@ from fontTools.ttLib.tables._g_l_y_f import flagOnCurve, flagCubic from fontTools.ttLib.tables._g_l_y_f import Glyph from fontTools.ttLib.tables._g_l_y_f import GlyphComponent from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates +from fontTools.ttLib.tables._g_l_y_f import dropImpliedOnCurvePoints import math __all__ = ["TTGlyphPen", "TTGlyphPointPen"] -def drop_implied_oncurves(*interpolatable_glyphs): - drop = None - for glyph in interpolatable_glyphs: - may_drop = set() - start = 0 - flags = glyph.flags - coords = glyph.coordinates - for last in glyph.endPtsOfContours: - for i in range(start, last + 1): - if not (flags[i] & flagOnCurve): - continue - prv = i - 1 if i > start else last - nxt = i + 1 if i < last else start - if (flags[prv] & flagOnCurve) or flags[prv] != flags[nxt]: - continue - p0 = coords[prv] - p1 = coords[i] - p2 = coords[nxt] - if not math.isclose(p1[0] - p0[0], p2[0] - p1[0]) or not math.isclose( - p1[1] - p0[1], p2[1] - p1[1] - ): - continue - - may_drop.add(i) - # we only want to drop if ALL interpolatable glyphs have the same implied oncurves - if drop is None: - drop = may_drop - else: - drop.intersection_update(may_drop) - - if drop: - # Do the actual dropping - for glyph in interpolatable_glyphs: - glyph.coordinates = GlyphCoordinates( - coords[i] for i in range(len(coords)) if i not in drop - ) - glyph.flags = array("B", (flags[i] for i in range(len(flags)) if i not in drop)) - - endPts = glyph.endPtsOfContours - newEndPts = [] - i = 0 - delta = 0 - for d in sorted(drop): - while d > endPts[i]: - newEndPts.append(endPts[i] - delta) - i += 1 - delta += 1 - while i < len(endPts): - newEndPts.append(endPts[i] - delta) - i += 1 - glyph.endPtsOfContours = newEndPts - - class _TTGlyphBasePen: def __init__( self, @@ -199,7 +147,7 @@ class _TTGlyphBasePen: glyph.coordinates.toInt() if dropImpliedOnCurves: - drop_implied_oncurves(glyph) + dropImpliedOnCurvePoints(glyph) self.init() diff --git a/Lib/fontTools/ttLib/tables/_g_l_y_f.py b/Lib/fontTools/ttLib/tables/_g_l_y_f.py index f71fd3e2d..48c08df3a 100644 --- a/Lib/fontTools/ttLib/tables/_g_l_y_f.py +++ b/Lib/fontTools/ttLib/tables/_g_l_y_f.py @@ -22,6 +22,7 @@ import sys import struct import array import logging +import math import os from fontTools.misc import xmlWriter from fontTools.misc.filenames import userNameToFileName @@ -1530,6 +1531,62 @@ class Glyph(object): return result if result is NotImplemented else not result +def dropImpliedOnCurvePoints(*interpolatable_glyphs): + drop = None + for glyph in interpolatable_glyphs: + may_drop = set() + start = 0 + flags = glyph.flags + coords = glyph.coordinates + for last in glyph.endPtsOfContours: + for i in range(start, last + 1): + if not (flags[i] & flagOnCurve): + continue + prv = i - 1 if i > start else last + nxt = i + 1 if i < last else start + if (flags[prv] & flagOnCurve) or flags[prv] != flags[nxt]: + continue + p0 = coords[prv] + p1 = coords[i] + p2 = coords[nxt] + if not math.isclose(p1[0] - p0[0], p2[0] - p1[0]) or not math.isclose( + p1[1] - p0[1], p2[1] - p1[1] + ): + continue + + may_drop.add(i) + # we only want to drop if ALL interpolatable glyphs have the same implied oncurves + if drop is None: + drop = may_drop + else: + drop.intersection_update(may_drop) + + if drop: + # Do the actual dropping + for glyph in interpolatable_glyphs: + coords = glyph.coordinates + glyph.coordinates = GlyphCoordinates( + coords[i] for i in range(len(coords)) if i not in drop + ) + glyph.flags = array.array( + "B", (flags[i] for i in range(len(flags)) if i not in drop) + ) + + endPts = glyph.endPtsOfContours + newEndPts = [] + i = 0 + delta = 0 + for d in sorted(drop): + while d > endPts[i]: + newEndPts.append(endPts[i] - delta) + i += 1 + delta += 1 + while i < len(endPts): + newEndPts.append(endPts[i] - delta) + i += 1 + glyph.endPtsOfContours = newEndPts + + class GlyphComponent(object): """Represents a component within a composite glyph.