def doit(args) : ''' This will add the following glyph to the font <?xml version="1.0" encoding="UTF-8"?> <glyph name="Test" format="1"> <unicode hex="007D"/> <outline> <contour> <point x="275" y="1582" type="line"/> <point x="275" y="-493" type="line"/> </contour> </outline> </glyph> ''' font = args.ifont # Create basic glyph newglyph = ufo.Uglif(layer = font.deflayer, name = "Test") newglyph.add("unicode", {"hex": "007D"}) # Add an outline newglyph.add("outline") # Create a contour and add to outline element = ET.Element("contour") ET.SubElement(element, "point", {"x": "275", "y": "1582", "type": "line"}) ET.SubElement(element, "point", {"x": "275", "y": "-493", "type": "line"}) contour =ufo.Ucontour(newglyph["outline"],element) newglyph["outline"].appendobject(contour, "contour") font.deflayer.addGlyph(newglyph) return args.ifont
def doit(args) : global glyphlist infont = args.ifont if args.report: infont.logger.loglevel = args.report removeRE = re.compile(args.remove) if args.remove else None preserveRE = re.compile(args.preserve) if args.preserve else None ### temp section (these may someday be passed as optional parameters) RemoveUsedAnchors = True ### end of temp section cgobj = CompGlyph() for linenum, rawCDline in enumerate(args.cdfile): CDline=rawCDline.strip() if len(CDline) == 0 or CDline[0] == "#": continue infont.logger.log("Processing line " + str(linenum+1) + ": " + CDline,"I") cgobj.CDline=CDline try: cgobj.parsefromCDline() except ValueError as mess: infont.logger.log("Parsing error: " + str(mess), "E") continue g = cgobj.CDelement # Collect target glyph information and construct list of component glyphs targetglyphname = g.get("PSName") targetglyphunicode = g.get("UID") glyphlist = [] # list of component glyphs lsb = rsb = 0 adv = None for e in g: if e.tag == 'note': pass elif e.tag == 'property': pass # ignore mark info elif e.tag == 'lsb': lsb = int(e.get('width')) elif e.tag == 'rsb': rsb = int(e.get('width')) elif e.tag == 'advance': adv = int(e.get('width')) elif e.tag == 'base': addtolist(e,None) infont.logger.log(str(glyphlist),"V") # find each component glyph and compute x,y position xbase = xadvance = lsb ybase = 0 componentlist = [] targetglyphanchors = {} # dictionary of {name: (xOffset,yOffset)} for currglyph, prevglyph, baseAP, diacAP, shiftx, shifty in glyphlist: # get current glyph and its anchor names from font if currglyph not in infont.deflayer: infont.logger.log(currglyph + " not found in font", "E") continue cg = infont.deflayer[currglyph] cganc = [x.element.get('name') for x in cg['anchor']] diacAPx = diacAPy = 0 baseAPx = baseAPy = 0 if prevglyph is None: # this is new 'base' xbase = xadvance xOffset = xbase yOffset = 0 # Find advance width of currglyph and add to xadvance if 'advance' in cg: cgadvance = cg['advance'] if cgadvance is not None and cgadvance.element.get('width') is not None: xadvance += int(float(cgadvance.element.get('width'))) else: # this is 'attach' if diacAP is not None: # find diacritic Attachment Point in currglyph if diacAP not in cganc: infont.logger.log("The AP '" + diacAP + "' does not exist on diacritic glyph " + currglyph, "E") else: i = cganc.index(diacAP) diacAPx = int(float(cg['anchor'][i].element.get('x'))) diacAPy = int(float(cg['anchor'][i].element.get('y'))) else: infont.logger.log("No AP specified for diacritic " + currglyph, "E") if baseAP is not None: # find base character Attachment Point in targetglyph if baseAP not in targetglyphanchors.keys(): infont.logger.log("The AP '" + baseAP + "' does not exist on base glyph when building " + targetglyphname, "E") else: baseAPx = targetglyphanchors[baseAP][0] baseAPy = targetglyphanchors[baseAP][1] if RemoveUsedAnchors: infont.logger.log("Removing used anchor " + baseAP, "V") del targetglyphanchors[baseAP] xOffset = baseAPx - diacAPx yOffset = baseAPy - diacAPy if shiftx is not None: xOffset += int(shiftx) if shifty is not None: yOffset += int(shifty) componentdic = {'base': currglyph} if xOffset != 0: componentdic['xOffset'] = str(xOffset) if yOffset != 0: componentdic['yOffset'] = str(yOffset) componentlist.append( componentdic ) # Move anchor information to targetglyphanchors for a in cg['anchor']: dic = a.element.attrib thisanchorname = dic['name'] if RemoveUsedAnchors and thisanchorname == diacAP: infont.logger.log("Skipping used anchor " + diacAP, "V") continue # skip this anchor # add anchor (adjusted for position in targetglyph) targetglyphanchors[thisanchorname] = ( int( dic['x'] ) + xOffset, int( dic['y'] ) + yOffset ) infont.logger.log("Adding anchor " + thisanchorname + ": " + str(targetglyphanchors[thisanchorname]), "V") infont.logger.log(str(targetglyphanchors),"V") if adv is not None: xadvance = adv ### if adv specified, then this advance value overrides calculated value else: xadvance += rsb ### adjust with rsb infont.logger.log("Glyph: " + targetglyphname + ", " + str(targetglyphunicode) + ", " + str(xadvance), "V") for c in componentlist: infont.logger.log(str(c), "V") # Flatten components unless -n set if not args.noflatten: newcomponentlist = [] for compdic in componentlist: c = compdic['base'] x = compdic.get('xOffset') y = compdic.get('yOffset') # look up component glyph g=infont.deflayer[c] # check if it has only components (that is, no contours) in outline if g['outline'] and g['outline'].components and not g['outline'].contours: # for each component, get base, x1, y1 and create new entry with base, x+x1, y+y1 for subcomp in g['outline'].components: componentdic = subcomp.element.attrib.copy() x1 = componentdic.pop('xOffset', 0) y1 = componentdic.pop('yOffset', 0) xOffset = addtwo(x, x1) yOffset = addtwo(y, y1) if xOffset != 0: componentdic['xOffset'] = str(xOffset) if yOffset != 0: componentdic['yOffset'] = str(yOffset) newcomponentlist.append( componentdic ) else: newcomponentlist.append( compdic ) if componentlist == newcomponentlist: infont.logger.log("No changes to flatten components", "V") else: componentlist = newcomponentlist infont.logger.log("Components flattened", "V") for c in componentlist: infont.logger.log(str(c), "V") # Check if this new glyph exists in the font already; if so, decide whether to replace, or issue warning preservedAPs = set() if targetglyphname in infont.deflayer.keys(): infont.logger.log("Target glyph, " + targetglyphname + ", already exists in font.", "V") targetglyph = infont.deflayer[targetglyphname] if targetglyph['outline'] and targetglyph['outline'].contours and not args.force: # don't replace glyph with contours, unless -f set infont.logger.log("Not replacing existing glyph, " + targetglyphname + ", because it has contours.", "W") continue else: infont.logger.log("Replacing information in existing glyph, " + targetglyphname, "V") # delete information from existing glyph targetglyph.remove('outline') targetglyph.remove('advance') for i in xrange(len(targetglyph['anchor'])-1,-1,-1): aname = targetglyph['anchor'][i].element.attrib['name'] if preserveRE is not None and preserveRE.match(aname): preservedAPs.add(aname) infont.logger.log("Preserving anchor " + aname, "V") else: targetglyph.remove('anchor',index=i) else: infont.logger.log("Adding new glyph, " + targetglyphname, "V") # create glyph, using targetglyphname, targetglyphunicode targetglyph = ufo.Uglif(layer=infont.deflayer, name=targetglyphname) # actually add the glyph to the font infont.deflayer.addGlyph(targetglyph) targetglyph.add('advance',{'width': str(xadvance)} ) if targetglyphunicode: # remove any existing unicode value(s) before adding unicode value for i in xrange(len(targetglyph['unicode'])-1,-1,-1): targetglyph.remove('unicode',index=i) targetglyph.add('unicode',{'hex': targetglyphunicode} ) targetglyph.add('outline') # to the outline element, add a component element for every entry in componentlist for compdic in componentlist: comp = ufo.Ucomponent(targetglyph['outline'],ET.Element('component',compdic)) targetglyph['outline'].appendobject(comp,'component') # copy anchors to new glyph from targetglyphanchors which has format {'U': (500,1000), 'L': (500,0)} for a in sorted(targetglyphanchors): if removeRE is not None and removeRE.match(a): infont.logger.log("Skipping unwanted anchor " + a, "V") continue # skip this anchor if a not in preservedAPs: targetglyph.add('anchor', {'name': a, 'x': str(targetglyphanchors[a][0]), 'y': str(targetglyphanchors[a][1])} ) # mark glyphs as being generated by setting cell mark color to dark green (if -c indicated) if args.color: lib = targetglyph["lib"] if lib is None: targetglyph.add("lib") targetglyph["lib"].setval("public.markColor", "string", "0.04,0.57,0.04,1") # If analysis only, return without writing output font if args.analysis: return # Return changed font and let execute() write it out return infont