def doit(args): ofile = args.output lfile = args.log filelinecount = 0 linecount = 0 elementcount = 0 cgobj = CompGlyph() f = ET.Element('font') for line in args.input.readlines(): filelinecount += 1 testline = line.strip() if len(testline ) > 0 and testline[0:1] != '#': # not whitespace or comment linecount += 1 cgobj.CDline = line cgobj.CDelement = None try: cgobj.parsefromCDline() if cgobj.CDelement != None: f.append(cgobj.CDelement) elementcount += 1 except ValueError as e: lfile.write("Line " + str(filelinecount) + ": " + str(e) + '\n') if linecount != elementcount: lfile.write("Lines read from input file: " + str(filelinecount) + '\n') lfile.write("Lines parsed (excluding blank and comment lines): " + str(linecount) + '\n') lfile.write("Valid glyphs found: " + str(elementcount) + '\n') # instead of simple serialization with: ofile.write(ET.tostring(f)) # create ETWriter object and specify indentation and attribute order to get normalized output indentFirst = " " indentIncr = " " attOrder = "PSName,UID,with,at,x,y" for k in args.params: if k == 'indentIncr': indentIncr = args.params['indentIncr'] elif k == 'indentFirst': indentFirst = args.params['indentFirst'] elif k == 'attOrder': attOrder = args.params['attOrder'] x = attOrder.split(',') attributeOrder = dict(zip(x, range(len(x)))) etwobj = ETWriter(f, indentFirst=indentFirst, indentIncr=indentIncr, attributeOrder=attributeOrder) ofile.write(etwobj.serialize_xml()) return
def doit(args) : ofile = args.output lfile = args.log filelinecount = 0 linecount = 0 elementcount = 0 cgobj = CompGlyph() f = ET.Element('font') for line in args.input.readlines(): filelinecount += 1 testline = line.strip() if len(testline) > 0 and testline[0] != '#': # not whitespace or comment linecount += 1 cgobj.CDline=line cgobj.CDelement=None try: cgobj.parsefromCDline() if cgobj.CDelement != None: f.append(cgobj.CDelement) elementcount += 1 except ValueError, e: lfile.write("Line "+str(filelinecount)+": "+str(e)+'\n')
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
def doit(args) : global glyphlist infont = args.ifont if args.report: infont.logger.loglevel = args.report ### temp section (these may someday be passed as optional parameters) RemoveUsedAnchors = True FlattenComponents = 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 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 ) # Find advance width of currglyph and add to xadvance cgadvance = cg['advance'] if 'advance' in cg else None if cgadvance is not None and cgadvance.element.get('width') is not None : xadvance += int(float(cgadvance.element.get('width'))) # 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("Skiping 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") xbase = xadvance + rsb ### adjust with rsb if adv is not None: xbase = adv ### if adv specified, then this advance value overrides calculated value infont.logger.log("Glyph: " + targetglyphname + ", " + str(targetglyphunicode) + ", " + str(xbase), "V") for c in componentlist: infont.logger.log(str(c), "V") # Flatten components if FlattenComponents: 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: b = subcomp.element.get('base') x1 = subcomp.element.get('xOffset') y1 = subcomp.element.get('yOffset') xOffset = addtwo(x, x1) yOffset = addtwo(y, y1) componentdic = {'base': b} 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 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): 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(xbase)} ) 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 targetglyphanchors: targetglyph.add('anchor', {'name': a, 'x': str(targetglyphanchors[a][0]), 'y': str(targetglyphanchors[a][1])} ) # If analysis only, return without writing output font if args.analysis: return # Return changed font and let execute() write it out return infont