def test_addComponent_decomposed(self): pen = DecomposingRecordingPen({"a": _TestGlyph()}) pen.addComponent("a", (2, 0, 0, 3, -10, 5)) assert pen.value == [ ('moveTo', ((-10.0, 5.0),)), ('lineTo', ((-10.0, 305.0),)), ('curveTo', ((90.0, 230.0), (110.0, 155.0), (90.0, 5.0),)), ('closePath', ())]
def _glyphsAreSame(glyphSet1, glyphSet2, glyph1, glyph2): pen1 = DecomposingRecordingPen(glyphSet1) pen2 = DecomposingRecordingPen(glyphSet2) g1 = glyphSet1[glyph1] g2 = glyphSet2[glyph2] g1.draw(pen1) g2.draw(pen2) return (pen1.value == pen2.value and g1.width == g2.width and (not hasattr(g1, 'height') or g1.height == g2.height))
def test_addComponent_decomposed(self): pen = DecomposingRecordingPen({"a": _TestGlyph()}) pen.addComponent("a", (2, 0, 0, 3, -10, 5)) assert pen.value == [ ("moveTo", ((-10.0, 5.0), )), ("lineTo", ((-10.0, 305.0), )), ("curveTo", ((90.0, 230.0), (110.0, 155.0), (90.0, 5.0))), ("closePath", ()), ]
def to_ufo_components_background_decompose(self, ufo_glyph, layer): """Draw decomposed .glyphs background components with a pen, adding them to the parent glyph.""" layer_id = layer.foreground.layerId layer_master_id = layer.foreground.associatedMasterId if layer_id in self._glyph_sets: layers = self._glyph_sets[layer_id] else: if layer_id == layer_master_id: # Is a master layer. layers = self._glyph_sets[layer_id] = { g.name: l for g in layer.parent.parent.glyphs for l in g.layers if l.layerId == layer_id } else: # Is a non-master layer. layers_nonmaster = { g.name: l for g in layer.parent.parent.glyphs for l in g.layers if l.name == layer.name } layers_master = { g.name: l for g in layer.parent.parent.glyphs for l in g.layers if l.layerId == layer_master_id } layers = self._glyph_sets[layer_id] = { **layers_master, **layers_nonmaster, } rpen = DecomposingRecordingPen(glyphSet=layers) for component in layer.components: try: component.draw(rpen) except MissingComponentError as e: raise MissingComponentError( f"Glyph '{ufo_glyph.name}', background layer: component " f"'{component.name}' points to a non-existent glyph." ) from e rpen.replay(ufo_glyph.getPen())
def ttfont_glyph_to_skia_path(glyph_name: str, tt_font: ttFont.TTFont) -> pathops.Path: """ Converts fontTools.ttLib.TTFont glyph to a pathops.Path object by glyph name. During this conversion, all composite paths are decomposed. """ glyf_table = tt_font["glyf"] glyph_set: ttFont._TTGlyphSet = tt_font.getGlyphSet() tt_glyph = glyf_table[glyph_name] skia_path = pathops.Path() skia_path_pen = skia_path.getPen() if tt_glyph.isComposite(): decompose_pen = DecomposingRecordingPen(glyph_set) glyph_set[glyph_name].draw(decompose_pen) decompose_pen.replay(skia_path_pen) return skia_path else: glyph_set[glyph_name].draw(skia_path_pen) return skia_path
def _glyphsAreSame(glyphSet1, glyphSet2, glyph1, glyph2, advanceTolerance=.05, advanceToleranceEmpty=.20): pen1 = DecomposingRecordingPen(glyphSet1) pen2 = DecomposingRecordingPen(glyphSet2) g1 = glyphSet1[glyph1] g2 = glyphSet2[glyph2] g1.draw(pen1) g2.draw(pen2) if pen1.value != pen2.value: return False # Allow more width tolerance for glyphs with no ink tolerance = advanceTolerance if pen1.value else advanceToleranceEmpty # TODO Warn if advances not the same but within tolerance. if abs(g1.width - g2.width) > g1.width * tolerance: return False if hasattr(g1, 'height') and g1.height is not None: if abs(g1.height - g2.height) > g1.height * tolerance: return False return True
def to_ufo_components_background_decompose(self, ufo_glyph, layer): """Draw decomposed .glyphs background components with a pen, adding them to the parent glyph.""" layer_id = layer.foreground.layerId layer_master_id = layer.foreground.associatedMasterId if layer_id in self._glyph_sets: layers = self._glyph_sets[layer_id] else: if layer_id == layer_master_id: # Is a master layer. layers = self._glyph_sets[layer_id] = { g.name: l for g in layer.parent.parent.glyphs for l in g.layers if l.layerId == layer_id } else: # Is a non-master layer. layers_nonmaster = { g.name: l for g in layer.parent.parent.glyphs for l in g.layers if l.name == layer.name } layers_master = { g.name: l for g in layer.parent.parent.glyphs for l in g.layers if l.layerId == layer_master_id } layers = self._glyph_sets[layer_id] = { **layers_master, **layers_nonmaster, } rpen = DecomposingRecordingPen(glyphSet=layers) for component in layer.components: component.draw(rpen) rpen.replay(ufo_glyph.getPen())
def decomposeAndRemoveOverlap(font, glyphName): glyfTable = font["glyf"] glyphSet = font.getGlyphSet() # record TTGlyph outlines without components dcPen = DecomposingRecordingPen(glyphSet) glyphSet[glyphName].draw(dcPen) # replay recording onto a skia-pathops Path path = pathops.Path() pathPen = path.getPen() dcPen.replay(pathPen) # remove overlaps path.simplify() # create new TTGlyph from Path ttPen = TTGlyphPen(None) path.draw(ttPen) glyfTable[glyphName] = ttPen.glyph()
def getVectorControl(self, char): """ グリフ情報からベクタ画像用の制御点情報を抽出する --- Parameters --- char : ターゲットの1文字 --- Return --- 制御点情報 """ #recording_pen = RecordingPen() recording_pen = DecomposingRecordingPen(self.glyph_set) obj = self.getGlyph(char) obj.draw(recording_pen) return recording_pen.value
def process_font(input_path, output_path=None, verbose=False): """ De-componentize a single font at input_path, saving to output_path (or input_path if None) """ font = TTFont(input_path) output_path = output_path or input_path gs = font.getGlyphSet() drpen = DecomposingRecordingPen(gs) ttgpen = TTGlyphPen(gs) count = 0 for glyphname in font.glyphOrder: glyph = font["glyf"][glyphname] if not glyph.isComposite(): continue if verbose: print(f" decomposing '{glyphname}'") # reset the pens drpen.value = [] ttgpen.init() # draw the composite glyph into the decomposing pen glyph.draw(drpen, font["glyf"]) # replay the recorded decomposed glyph into the TTGlyphPen drpen.replay(ttgpen) # store the decomposed glyph in the 'glyf' table font["glyf"][glyphname] = ttgpen.glyph() count += 1 font.save(output_path) return count
print("usage: decompose-ttf.py fontfile.ttf outfile.ttf") sys.exit(1) src = sys.argv[1] dst = sys.argv[2] with TTFont(src) as f: glyfTable = f["glyf"] glyphSet = f.getGlyphSet() for glyphName in glyphSet.keys(): if not glyfTable[glyphName].isComposite(): continue # record TTGlyph outlines without components dcPen = DecomposingRecordingPen(glyphSet) glyphSet[glyphName].draw(dcPen) # replay recording onto a skia-pathops Path path = pathops.Path() pathPen = path.getPen() dcPen.replay(pathPen) # remove overlaps path.simplify() # create new TTGlyph from Path ttPen = TTGlyphPen(None) path.draw(ttPen) glyfTable[glyphName] = ttPen.glyph()
def test_addComponent_missing_raises(self): pen = DecomposingRecordingPen(dict()) with pytest.raises(KeyError) as excinfo: pen.addComponent("a", (1, 0, 0, 1, 0, 0)) assert excinfo.value.args[0] == "a"
def test_addComponent_missing_raises(self): pen = DecomposingRecordingPen(dict()) with pytest.raises(KeyError) as excinfo: pen.addComponent("a", (1, 0, 0, 1, 0, 0)) assert excinfo.value.args[0] == "a"