def doit(args) : font = args.font logger = args.logger newversion = args.newversion fi = font.fontinfo otelem = fi["openTypeNameVersion"][1] if "openTypeNameVersion" in fi else None majelem = fi["versionMajor"][1] if "versionMajor" in fi else None minelem = fi["versionMinor"][1] if "versionMinor" in fi else None otnv = None if otelem is None else otelem.text vmaj = None if majelem is None else majelem.text vmin = None if minelem is None else minelem.text if otnv is None or vmaj is None or vmin is None : logger.log("At least one of openTypeNameVersion, versionMajor or versionMinor missing fron fontinfo.plist", "S") if newversion is None: if otnvre.match(otnv) is None: logger.log("Current version is '" + otnv + "' which is non-standard", "E") else : logger.log("Current version is '" + otnv + "'", "P") (otmaj,otmin,otextrainfo) = parseotnv(otnv) if (otmaj, int(otmin)) != (vmaj,int(vmin)) : logger.log("openTypeNameVersion values don't match versionMajor (" + vmaj + ") and versionMinor (" + vmin + ")", "E") else: if newversion[0] == "+" : if otnvre.match(otnv) is None: logger.log("Current openTypeNameVersion is non-standard so can't be incremented: " + otnv , "S") else : (otmaj,otmin,otextrainfo) = parseotnv(otnv) if (otmaj, int(otmin)) != (vmaj,int(vmin)) : logger.log("openTypeNameVersion (" + otnv + ") doesn't match versionMajor (" + vmaj + ") and versionMinor (" + vmin + ")", "S") # Process increment to versionMinor. Note vmin is treated as 3 digit mpp where m and pp are minor and patch versions respectively increment = newversion[1:] if increment not in ("1", "0.001", ".001", "0.1", ".1") : logger.log("Invalid increment value - must be one of 1, 0.001, .001, 0.1 or .1", "S") increment = 100 if increment in ("0.1", ".1") else 1 if (increment == 100 and vmin[0] == "9") or (increment == 1 and vmin[1:2] == "99") : logger.log("Version already at maximum so can't be incremented", "S") otmin = str(int(otmin) + increment).zfill(3) else : newversion = "Version " + newversion if otnvre.match(newversion) is None: logger.log("newversion format invalid - should be 'M.mpp' or 'M.mpp extrainfo'", "S") else : (otmaj,otmin,otextrainfo) = parseotnv(newversion) newotnv = "Version " + otmaj + "." + otmin + otextrainfo # Extrainfo already as leading space logger.log("Updating version from '" + otnv + "' to '" + newotnv + "'","P") # Update and write to disk otelem.text = newotnv majelem.text = otmaj minelem.text = otmin UFO.writeXMLobject(fi,font.outparams,font.ufodir, "fontinfo.plist" , True, fobject = True) return
def doit(args) : font = args.font logger = args.logger newversion = args.newversion fi = font.fontinfo otelem = fi["openTypeNameVersion"][1] if "openTypeNameVersion" in fi else None majelem = fi["versionMajor"][1] if "versionMajor" in fi else None minelem = fi["versionMinor"][1] if "versionMinor" in fi else None otnv = None if otelem is None else otelem.text vmaj = None if majelem is None else majelem.text vmin = None if minelem is None else minelem.text if otnv is None or vmaj is None or vmin is None : logger.log("At least one of openTypeNameVersion, versionMajor or versionMinor missing fron fontinfo.plist", "S") if newversion is None: if otnvre.match(otnv) is None: logger.log("Current version is '" + otnv + "' which is non-standard", "E") else : logger.log("Current version is '" + otnv + "'", "P") (otmaj,otmin,otextrainfo) = parseotnv(otnv) if (otmaj, int(otmin)) != (vmaj,int(vmin)) : logger.log("openTypeNameVersion values don't match versionMajor (" + vmaj + ") and versionMinor (" + vmin + ")", "E") else: if newversion[0:1] == "+" : if otnvre.match(otnv) is None: logger.log("Current openTypeNameVersion is non-standard so can't be incremented: " + otnv , "S") else : (otmaj,otmin,otextrainfo) = parseotnv(otnv) if (otmaj, int(otmin)) != (vmaj,int(vmin)) : logger.log("openTypeNameVersion (" + otnv + ") doesn't match versionMajor (" + vmaj + ") and versionMinor (" + vmin + ")", "S") # Process increment to versionMinor. Note vmin is treated as 3 digit mpp where m and pp are minor and patch versions respectively increment = newversion[1:] if increment not in ("1", "0.001", ".001", "0.1", ".1") : logger.log("Invalid increment value - must be one of 1, 0.001, .001, 0.1 or .1", "S") increment = 100 if increment in ("0.1", ".1") else 1 if (increment == 100 and vmin[0:1] == "9") or (increment == 1 and vmin[1:2] == "99") : logger.log("Version already at maximum so can't be incremented", "S") otmin = str(int(otmin) + increment).zfill(3) else : newversion = "Version " + newversion if otnvre.match(newversion) is None: logger.log("newversion format invalid - should be 'M.mpp' or 'M.mpp extrainfo'", "S") else : (otmaj,otmin,otextrainfo) = parseotnv(newversion) newotnv = "Version " + otmaj + "." + otmin + otextrainfo # Extrainfo already as leading space logger.log("Updating version from '" + otnv + "' to '" + newotnv + "'","P") # Update and write to disk otelem.text = newotnv majelem.text = otmaj minelem.text = otmin UFO.writeXMLobject(fi,font.outparams,font.ufodir, "fontinfo.plist" , True, fobject = True) return
def write(self, plistn): filen = plistn + self.newfile + ".plist" self.logger.log("Writing updated " + plistn + ".plist to " + filen, "P") exists = True if os.path.isfile(os.path.join(self.ufodir, filen)) else False plist = getattr(self, plistn) UFO.writeXMLobject(plist, self.outparams, self.ufodir, filen, exists, fobject=True)
def doit(args) : standardstyles = ["Regular", "Italic", "Bold", "BoldItalic"] finfoignore = ["openTypeHeadCreated", "openTypeOS2Panose", "postscriptBlueScale", "postscriptBlueShift", "postscriptBlueValues", "postscriptOtherBlues", "postscriptStemSnapH", "postscriptStemSnapV", "postscriptForceBold"] libfields = ["public.postscriptNames", "public.glyphOrder", "com.schriftgestaltung.glyphOrder"] font = args.ifont logger = args.logger singlefont = args.single mfont = args.master newfile = "_new" if args.new else "" reportonly = args.reportonly updatemessage = " to be updated: " if reportonly else " updated: " params = args.paramsobj precision = font.paramset["precision"] # Increase screen logging level to W unless specific level supplied on command-line if not(args.quiet or "scrlevel" in params.sets["command line"]) : logger.scrlevel = "W" # Process UFO name (path,base) = os.path.split(font.ufodir) (base,ext) = os.path.splitext(base) if '-' not in base : logger.log("Non-standard UFO name - must be <family>-<style>", "S") (family,style) = base.split('-') styles = [style] fonts = {} fonts[style] = font # Process single and master settings if singlefont : if mfont : mastertext = "Master" # Used in log messages else : # Check against Regular font from same family mfont = openfont(params, path, family, "Regular") if mfont is None : logger.log("No regular font to check against - use -m to specify master font", "S") mastertext = "Regular" fonts["Regular"] =mfont else : # Supplied font must be Regular if mfont : logger.log("-m --master must only be used with -s --single", "S") if style != "Regular" : logger.log("Must specify a Regular font unless -s is used", "S") mastertext = "Regular" mfont = font # Check for required fields in master font mfinfo = mfont.fontinfo if "familyName" in mfinfo : spacedfamily = mfinfo["familyName"][1].text else: logger.log("No familyName field in " + mastertext, "S") if "openTypeNameManufacturer" in mfinfo : manufacturer = mfinfo["openTypeNameManufacturer"][1].text else: logger.log("No openTypeNameManufacturer field in " + mastertext, "S") mlib = mfont.lib # Open the remaining fonts in the family if not singlefont : for style in standardstyles : if not style in fonts : fonts[style] = openfont(params, path, family, style) # Will return None if font does not exist if fonts[style] is not None : styles.append(style) # Process fonts psuniqueidlist = [] fieldscopied = False for style in styles : font = fonts[style] if font.UFOversion != "2" : logger.log("This script only works with UFO 2 format fonts","S") fontname = family + "-" + style spacedstyle = "Bold Italic" if style == "BoldItalic" else style spacedname = spacedfamily + " " + spacedstyle logger.log("************ Processing " + fontname, "P") ital = True if "Italic" in style else False bold = True if "Bold" in style else False # Process fontinfo.plist finfo=font.fontinfo fieldlist = list(set(finfo) | set(mfinfo)) # Need all fields from both to detect missing fields fchanged = False for field in fieldlist: action = None; issue = ""; newval = "" if field in finfo : elem = finfo[field][1] tag = elem.tag text = elem.text if text is None : text = "" if tag == "real" : text = processnum(text,precision) # Field-specific actions if field not in finfo : if field not in finfoignore : action = "Copyfield" elif field == "italicAngle" : if ital and text == "0" : issue = "is zero" action = "Warn" if not ital and text != "0" : issue = "is non-zero" newval = 0 action = "Update" elif field == "openTypeNameUniqueID" : newval = manufacturer + ": " + spacedname + ": " + datetime.now().strftime("%Y") if text != newval : issue = "Incorrect value" action = "Update" elif field == "openTypeOS2WeightClass" : if bold and text != "700" : issue = "is not 700" newval = 700 action = "Update" if not bold and text != "400" : issue = "is not 400" newval = 400 action = "Update" elif field == "postscriptFontName" : if text != fontname : newval = fontname issue = "Incorrect value" action = "Update" elif field == "postscriptFullName" : if text != spacedname : newval = spacedname issue = "Incorrect value" action = "Update" elif field == "postscriptUniqueID" : if text in psuniqueidlist : issue = "has same value as another font: " + text action = "Warn" else : psuniqueidlist.append(text) elif field == "postscriptWeightName" : newval = 'bold' if bold else 'regular' if text != newval : issue = "Incorrect value" action = 'Update' elif field == "styleMapStyleName" : if text != spacedstyle.lower() : newval = spacedstyle.lower() issue = "Incorrect value" action = "Update" elif field in ("styleName", "openTypeNamePreferredSubfamilyName") : if text != spacedstyle : newval = spacedstyle issue = "Incorrect value" action = "Update" elif field in finfoignore : action = "Ignore" # Warn for fields in this font but not master elif field not in mfinfo : issue = "is in " + spacedstyle + " but not in " + mastertext action = "Warn" # for all other fields, sync values from master else : melem = mfinfo[field][1] mtag = melem.tag mtext = melem.text if mtext is None : mtext = "" if mtag is 'real' : mtext = processnum(mtext,precision) if tag in ("real", "integer", "string") : if mtext != text : issue = "does not match " + mastertext + " value" newval = mtext action = "Update" elif tag in ("true, false") : if tag != mtag : issue = "does not match " + mastertext + " value" action = "FlipBoolean" elif tag == "array" : # Assume simple array with just values to compare marray = mfinfo.getval(field) array = finfo.getval(field) if array != marray: action = "CopyArray" else : logger.log("Non-standard fontinfo field type in " + fontname, "X") # Now process the actions, create log messages etc if action is None or action == "Ignore" : pass elif action == "Warn" : logger.log(field + " needs manual correction: " + issue, "W") elif action == "Error" : logger.log(field + " needs manual correction: " + issue, "E") elif action in ("Update", "FlipBoolean", "Copyfield", "CopyArray") : # Updating actions fchanged = True message = field + updatemessage if action == "Update" : message = message + issue + " Old: '" + text + "' New: '" + str(newval) + "'" elem.text = newval elif action == "FlipBoolean" : newval = "true" if tag == "false" else "false" message = message + issue + " Old: '" + tag + "' New: '" + newval + "'" finfo.setelem(field, ET.fromstring("<" + newval + "/>")) elif action == "Copyfield" : message = message + "is missing so will be copied from " + mastertext fieldscopied = True finfo.addelem(field, ET.fromstring(ET.tostring(mfinfo[field][1]))) elif action == "CopyArray" : message = message + "Some values different Old: " + str(array) + " New: " + str(marray) finfo.setelem(field, ET.fromstring(ET.tostring(melem))) logger.log(message, "W") else: logger.log("Uncoded action: " + action + " - oops", "X") # Process lib.plist - currently just public.postscriptNames and glyph order fields which are all simple dicts or arrays lib = font.lib lchanged = False for field in libfields: # Check the values action = None; issue = ""; newval = "" if field in mlib: if field in lib: if lib.getval(field) != mlib.getval(field): # will only work for arrays or dicts with simple values action = "Updatefield" else: action = "Copyfield" else: action = "Error" if field == ("public.GlyphOrder", "public.postscriptNames") else "Warn" issue = field + " not in " + mastertext + " lib.plist" # Process the actions, create log messages etc if action is None or action == "Ignore": pass elif action == "Warn": logger.log(field + " needs manual correction: " + issue, "W") elif action == "Error": logger.log(field + " needs manual correction: " + issue, "E") elif action in ("Updatefield", "Copyfield"): # Updating actions lchanged = True message = field + updatemessage if action == "Copyfield": message = message + "is missing so will be copied from " + mastertext lib.addelem(field, ET.fromstring(ET.tostring(mlib[field][1]))) elif action == "Updatefield": message = message + "Some values different" lib.setelem(field, ET.fromstring(ET.tostring(mlib[field][1]))) logger.log(message, "W") else: logger.log("Uncoded action: " + action + " - oops", "X") # Now update on disk if not reportonly: if args.normalize: font.write(os.path.join(path, family + "-" + style + newfile + ".ufo")) else: # Just update fontinfo and lib if fchanged: filen = "fontinfo" + newfile + ".plist" logger.log("Writing updated fontinfo to " + filen, "P") exists = True if os.path.isfile(os.path.join(font.ufodir, filen)) else False UFO.writeXMLobject(finfo, font.outparams, font.ufodir, filen, exists, fobject=True) if lchanged: filen = "lib" + newfile + ".plist" logger.log("Writing updated lib.plist to " + filen, "P") exists = True if os.path.isfile(os.path.join(font.ufodir, filen)) else False UFO.writeXMLobject(lib, font.outparams, font.ufodir, filen, exists, fobject=True) if fieldscopied : message = "After updating, UFOsyncMeta will need to be re-run to validate these fields" if reportonly else "Re-run UFOsyncMeta to validate these fields" logger.log("*** Some fields were missing and so copied from " + mastertext + ". " + message, "P") return
def doit(args): font = args.font pfn = args.primaryname orgid = args.orgid fontlog = args.fontlog logger = args.logger ofn = args.output # Find & process info required in the UFO fi = font.fontinfo ufofields = {} missing = None for field in ("versionMajor", "versionMinor", "openTypeNameManufacturer", "openTypeNameManufacturerURL", "openTypeNameLicense", "copyright", "trademark"): if field in fi: ufofields[field] = fi[field][1].text elif field != 'trademark': # trademark is no longer required missing = field if missing is None else missing + ", " + field if missing is not None: logger.log("Field(s) missing from fontinfo.plist: " + missing, "S") version = ufofields["versionMajor"] + "." + ufofields["versionMinor"].zfill(3) # Find & process WOFF fields if present in the UFO missing = None ufowoff = {"woffMetadataCredits": "credits", "woffMetadataDescription": "text"} # Field, dict name for field in ufowoff: elem = fi[field][1] if field in fi else None if elem is None: missing = field if missing is None else missing + ", " + field ufofields[field] = None else: ufofields[field] = fi.getval(field)[ufowoff[field]] # Process --populateufowoff setting, if present if args.populateufowoff: if missing != "woffMetadataCredits, woffMetadataDescription" and not args.force: logger.log("Data exists in the UFO for woffMetadataCredits or woffMetadataDescription", "W") logger.log("Use --force to force update of those fields, or rerun without --populateufowoff", "S") if args.populateufowoff or missing is not None: # if missing: logger.log("WOFF field(s) missing from fontinfo.plist will be generated from FONTLOG.txt: " + missing, "W") # Parse the fontlog file (section, match) = readuntil(fontlog, ("Basic Font Information",)) # Skip until start of "Basic Font Information" section if match is None: logger.log("No 'Basic Font Information' section in fontlog", "S") (fldescription, match) = readuntil(fontlog, ("Information for C", "Acknowledgements")) # Desciption ends when first of these sections is found fldescription = [{"text": fldescription}] if match == "Information for C": (section, match) = readuntil(fontlog, ("Acknowledgements",)) # If Info... section present then skip on to Acknowledgements if match is None: logger.log("No 'Acknowledgements' section in fontlog", "S") (acksection, match) = readuntil(fontlog, ("No match needed!!",)) flcredits = [] credit = {} acktype = "" flog2woff = {"N": "name", "E": "Not used", "W": "url", "D": "role"} for line in acksection.splitlines(): if line == "": if acktype != "": # Must be at the end of a credit section if "name" in credit: flcredits.append(credit) else: logger.log("Credit section found with no N: entry", "E") credit = {} acktype = "" else: match = re.match("^([NEWD]): (.*)", line) if match is None: if acktype == "N": credit["name"] = credit["name"] + line # Name entries can be multiple lines else: acktype = match.group(1) if acktype in credit: logger.log("Multiple " + acktype + " entries found in a credit section", "E") else: credit[flog2woff[acktype]] = match.group(2) if flcredits == []: logger.log("No credits found in fontlog", "S") if args.populateufowoff: ufofields["woffMetadataDescription"] = fldescription # Force fontlog values to be used writing metatdata.xml later ufofields["woffMetadataCredits"] = flcredits # Create xml strings and update fontinfo xmlstring = "<dict><key>text</key><array><dict><key>text</key><string>" + textprotect(fldescription[0]["text"]) \ + "</string></dict></array></dict>" fi.setelem("woffMetadataDescription", ET.fromstring(xmlstring)) xmlstring = "<dict><key>credits</key><array>" for credit in flcredits: xmlstring += '<dict><key>name</key><string>' + textprotect(credit["name"]) + '</string>' if "url" in credit: xmlstring += '<key>url</key><string>' + textprotect(credit["url"]) + '</string>' if "role" in credit: xmlstring += '<key>role</key><string>' + textprotect(credit["role"]) + '</string>' xmlstring += '</dict>' xmlstring += '</array></dict>' fi.setelem("woffMetadataCredits", ET.fromstring(xmlstring)) fi.setval("openTypeHeadCreated", "string", datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")) logger.log("Writing updated fontinfo.plist with values from FONTLOG.txt", "P") exists = True if os.path.isfile(os.path.join(font.ufodir, "fontinfo.plist")) else False UFO.writeXMLobject(fi, font.outparams, font.ufodir, "fontinfo.plist", exists, fobject=True) description = ufofields["woffMetadataDescription"] if description == None: description = fldescription credits = ufofields["woffMetadataCredits"] if credits == None : credits = flcredits # Construct output file name (folder, ufoname) = os.path.split(font.ufodir) filename = os.path.join(folder, pfn + "-WOFF-metadata.xml") if ofn is None else ofn try: file = open(filename, "w") except Exception as e: logger.log("Unable to open " + filename + " for writing:\n" + str(e), "S") logger.log("Writing to : " + filename, "P") file.write('<?xml version="1.0" encoding="UTF-8"?>\n') file.write('<metadata version="1.0">\n') file.write(' <uniqueid id="' + orgid + '.' + pfn + '.' + version + '" />\n') file.write(' <vendor name="' + attrprotect(ufofields["openTypeNameManufacturer"]) + '" url="' + attrprotect(ufofields["openTypeNameManufacturerURL"]) + '" />\n') file.write(' <credits>\n') for credit in credits: file.write(' <credit\n') file.write(' name="' + attrprotect(credit["name"]) + '"\n') if "url" in credit: file.write(' url="' + attrprotect(credit["url"]) + '"\n') if "role" in credit: file.write(' role="' + attrprotect(credit["role"]) + '"\n') file.write(' />\n') file.write(' </credits>\n') file.write(' <description>\n') file.write(' <text lang="en">\n') for entry in description: for line in entry["text"].splitlines(): file.write(' ' + textprotect(line) + '\n') file.write(' </text>\n') file.write(' </description>\n') file.write(' <license url="http://scripts.sil.org/OFL" id="org.sil.ofl.1.1">\n') file.write(' <text lang="en">\n') for line in ufofields["openTypeNameLicense"].splitlines(): file.write(' ' + textprotect(line) + '\n') file.write(' </text>\n') file.write(' </license>\n') file.write(' <copyright>\n') file.write(' <text lang="en">\n') for line in ufofields["copyright"].splitlines(): file.write(' ' + textprotect(line) + '\n') file.write(' </text>\n') file.write(' </copyright>\n') if 'trademark' in ufofields: file.write(' <trademark>\n') file.write(' <text lang="en">' + textprotect(ufofields["trademark"]) + '</text>\n') file.write(' </trademark>\n') file.write('</metadata>') file.close()
def doit(args) : fields = ["copyright", "openTypeNameDescription", "openTypeNameDesigner", "openTypeNameDesignerURL", "openTypeNameLicense", # General feilds "openTypeNameLicenseURL", "openTypeNameManufacturer", "openTypeNameManufacturerURL", "openTypeOS2CodePageRanges", "openTypeOS2UnicodeRanges", "openTypeOS2VendorID", "trademark", "openTypeNameVersion", "versionMajor", "versionMinor", # Version fields "ascender", "descender", "openTypeHheaAscender", "openTypeHheaDescender", "openTypeHheaLineGap", # Design fields "openTypeOS2TypoAscender", "openTypeOS2TypoDescender", "openTypeOS2TypoLineGap", "openTypeOS2WinAscent", "openTypeOS2WinDescent"] libfields = ["public.postscriptNames", "public.glyphOrder", "com.schriftgestaltung.glyphOrder"] fromfont = args.fromfont tofont = args.tofont logger = args.logger reportonly = args.reportonly updatemessage = " to be updated: " if reportonly else " updated: " precision = fromfont.paramset["precision"] # Increase screen logging level to W unless specific level supplied on command-line if not(args.quiet or "scrlevel" in args.paramsobj.sets["command line"]) : logger.scrlevel = "W" # Process fontinfo.plist ffi = fromfont.fontinfo tfi = tofont.fontinfo fupdated = False for field in fields: if field in ffi : felem = ffi[field][1] ftag = felem.tag ftext = felem.text if ftag is 'real' : ftext = processnum(ftext,precision) message = field + updatemessage if field in tfi : # Need to compare values to see if update is needed telem = tfi[field][1] ttag = telem.tag ttext = telem.text if ttag is 'real' : ttext = processnum(ttext,precision) if ftag in ("real", "integer", "string") : if ftext != ttext : if field == "openTypeNameLicense" : # Too long to display all addmess = " Old: '" + ttext[0:80] + "...' New: '" + ftext[0:80] + "...'" else: addmess = " Old: '" + ttext + "' New: '" + str(ftext) + "'" telem.text = ftext logger.log(message + addmess, "W") fupdated = True elif ftag in ("true, false") : if ftag != ttag : fti.setelem(field, ET.fromstring("<" + ftag + "/>")) logger.log(message + " Old: '" + ttag + "' New: '" + str(ftag) + "'", "W") fupdated = True elif ftag == "array" : # Assume simple array with just values to compare farray = [] for subelem in felem : farray.append(subelem.text) tarray = [] for subelem in telem : tarray.append(subelem.text) if farray != tarray : tfi.setelem(field, ET.fromstring(ET.tostring(felem))) logger.log(message + "Some values different Old: " + str(tarray) + " New: " + str(farray), "W") fupdated = True else : logger.log("Non-standard fontinfo field type: "+ ftag + " in " + fontname, "S") else : tfi.addelem(field, ET.fromstring(ET.tostring(felem))) logger.log(message + "is missing from destination font so will be copied from source font", "W") fupdated = True else: # Field not in from font if field in tfi : logger.log( field + " is missing from source font but present in destination font", "E") else : logger.log( field + " is in neither font", "W") # Process lib.plist - currently just public.postscriptNames and glyph order fields which are all simple dicts or arrays flib = fromfont.lib tlib = tofont.lib lupdated = False for field in libfields: action = None if field in flib: if field in tlib: # Need to compare values to see if update is needed if flib.getval(field) != tlib.getval(field): action = "Updatefield" else: action = "Copyfield" else: action = "Error" if field == ("public.GlyphOrder", "public.postscriptNames") else "Warn" issue = field + " not in source font lib.plist" # Process the actions, create log messages etc if action is None or action == "Ignore": pass elif action == "Warn": logger.log(field + " needs manual correction: " + issue, "W") elif action == "Error": logger.log(field + " needs manual correction: " + issue, "E") elif action in ("Updatefield", "Copyfield"): # Updating actions lupdated = True message = field + updatemessage if action == "Copyfield": message = message + "is missing so will be copied from source font" tlib.addelem(field, ET.fromstring(ET.tostring(flib[field][1]))) elif action == "Updatefield": message = message + "Some values different" tlib.setelem(field, ET.fromstring(ET.tostring(flib[field][1]))) logger.log(message, "W") else: logger.log("Uncoded action: " + action + " - oops", "X") # Now update on disk if not reportonly: if fupdated: logger.log("Writing updated fontinfo.plist", "P") UFO.writeXMLobject(tfi, tofont.outparams, tofont.ufodir, "fontinfo.plist", True, fobject=True) if lupdated: logger.log("Writing updated lib.plist", "P") UFO.writeXMLobject(tlib, tofont.outparams, tofont.ufodir, "lib.plist", True, fobject=True) return
def doit(args): fields = [ "copyright", "openTypeNameDescription", "openTypeNameDesigner", "openTypeNameDesignerURL", "openTypeNameLicense", # General feilds "openTypeNameLicenseURL", "openTypeNameManufacturer", "openTypeNameManufacturerURL", "openTypeOS2CodePageRanges", "openTypeOS2UnicodeRanges", "openTypeOS2VendorID", "trademark", "year", "openTypeNameVersion", "versionMajor", "versionMinor", # Version fields "ascender", "descender", "openTypeHheaAscender", "openTypeHheaDescender", "openTypeHheaLineGap", # Design fields "openTypeOS2TypoAscender", "openTypeOS2TypoDescender", "openTypeOS2TypoLineGap", "openTypeOS2WinAscent", "openTypeOS2WinDescent" ] fromfont = args.fromfont tofont = args.tofont logger = args.logger reportonly = args.reportonly ffi = fromfont.fontinfo tfi = tofont.fontinfo updatemessage = " to be updated: " if reportonly else " updated: " precision = fromfont.paramset["precision"] # Increase screen logging level to W unless specific level supplied on command-line if not (args.quiet or "scrlevel" in args.paramsobj.sets["command line"]): logger.scrlevel = "W" updated = False for field in fields: if field in ffi: felem = ffi[field][1] ftag = felem.tag ftext = felem.text if ftag is 'real': ftext = processnum(ftext, precision) message = field + updatemessage if field in tfi: # Need to compare values to see if update is needed telem = tfi[field][1] ttag = telem.tag ttext = telem.text if ttag is 'real': ttext = processnum(ttext, precision) if ftag in ("real", "integer", "string"): if ftext != ttext: if field == "openTypeNameLicense": # Too long to display all addmess = " Old: '" + ttext[ 0:80] + "...' New: '" + ftext[0:80] + "...'" else: addmess = " Old: '" + ttext + "' New: '" + str( ftext) + "'" telem.text = ftext logger.log(message + addmess, "W") updated = True elif ftag in ("true, false"): if ftag != ttag: fti.setelem(field, ET.fromstring("<" + ftag + "/>")) logger.log( message + " Old: '" + ttag + "' New: '" + str(ftag) + "'", "W") updated = True elif ftag == "array": # Assume simple array with just values to compare farray = [] for subelem in felem: farray.append(subelem.text) tarray = [] for subelem in telem: tarray.append(subelem.text) if farray != tarray: tfi.setelem(field, ET.fromstring(ET.tostring(felem))) logger.log( message + "Some values different Old: " + str(tarray) + " New: " + str(farray), "W") updated = True else: logger.log( "Non-standard fontinfo field type: " + ftag + " in " + fontname, "X") else: tfi.addelem(field, ET.fromstring(ET.tostring(felem))) logger.log( message + "is missing from destination font so will be copied from source font", "W") updated = True else: # Field not in from font if field in tfi: logger.log( field + " is missing from source font but present in destination font", "E") else: logger.log(field + " is in neither font", "W") # Now update on disk if not reportonly and updated: logger.log("Writing updated fontinfo.plist", "P") UFO.writeXMLobject(tfi, tofont, tofont.ufodir, "fontinfo.plist", True, fobject=True) return