def testInfo(self): self.setUpFont(doInfo=True) otherResults = self.compareToUFO(doInfo=False) self.assertEqual(otherResults["kerning"], False) self.assertEqual(otherResults["groups"], False) expectedPath = os.path.join(ufoPath1, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): self.assertEqual((attr, expectedValue), (attr, written[attr])) self.tearDownFont()
def exportGlyph(glyphName, flGlyph, glyphSet): """Export a FontLab glyph.""" glyph = GlyphPlaceholder() glyph.width = flGlyph.width glyph.unicodes = flGlyph.unicodes if flGlyph.note: glyph.note = flGlyph.note customdata = flGlyph.customdata if customdata: from cStringIO import StringIO from robofab.plistlib import readPlist, Data f = StringIO(customdata) try: glyph.lib = readPlist(f) except: # XXX ugh, plistlib can raise lots of things # Anyway, customdata does not contain valid plist data, # but we don't need to toss it! glyph.lib = {"org.robofab.fontlab.customdata": Data(customdata)} def drawPoints(pen): # whoohoo, nested scopes are cool. drawFLGlyphOntoPointPen(flGlyph, pen) glyphSet.writeGlyph(glyphName, glyph, drawPoints)
def readLib(self): """ Read lib.plist. Returns a dict. """ path = os.path.join(self._path, LIB_FILENAME) if not self._checkForFile(path): return {} return readPlist(path)
def readGroups(self): """ Read groups.plist. Returns a dict. """ path = os.path.join(self._path, GROUPS_FILENAME) if not self._checkForFile(path): return {} return readPlist(path)
def compareToUFO(self): readerExpected = UFOReader(ufoPath1) readerWritten = UFOReader(self.dstDir) results = {} # info matches = True expectedPath = os.path.join(ufoPath1, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") if not os.path.exists(writtenPath): matches = False else: expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): if expectedValue != written.get(attr): matches = False break results["info"] = matches # kerning matches = True expectedPath = os.path.join(ufoPath1, "kerning.plist") writtenPath = os.path.join(self.dstDir, "kerning.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["kerning"] = matches # groups matches = True expectedPath = os.path.join(ufoPath1, "groups.plist") writtenPath = os.path.join(self.dstDir, "groups.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["groups"] = matches # features matches = True expectedPath = os.path.join(ufoPath1, "features.fea") writtenPath = os.path.join(self.dstDir, "features.fea") if os.path.exists(writtenPath): matches = False results["features"] = matches # lib matches = True expectedPath = os.path.join(ufoPath1, "lib.plist") writtenPath = os.path.join(self.dstDir, "lib.plist") if not os.path.exists(writtenPath): matches = False else: writtenLib = readPlist(writtenPath) matches = readPlist(expectedPath) == writtenLib results["lib"] = matches return results
def convertUFOFormatVersion2ToFormatVersion1(inPath, outPath=None): """ Function for converting a version format 2 UFO to version format 1. inPath should be a path to a UFO. outPath is the path where the new UFO should be written. If outPath is not given, the inPath will be used and, therefore, the UFO will be converted in place. Otherwise, if outPath is specified, nothing must exist at that path. """ if outPath is None: outPath = inPath if inPath != outPath and os.path.exists(outPath): raise UFOLibError("A file already exists at %s." % outPath) # use a reader for loading most of the data reader = UFOReader(inPath) if reader.formatVersion == 1: raise UFOLibError("The UFO at %s is already format version 1." % inPath) groups = reader.readGroups() kerning = reader.readKerning() libData = reader.readLib() # read the info data manually and convert infoPath = os.path.join(inPath, FONTINFO_FILENAME) if not os.path.exists(infoPath): infoData = {} else: infoData = readPlist(infoPath) infoData = _convertFontInfoDataVersion2ToVersion1(infoData) # if the paths are the same, only need to change the # fontinfo, metainfo and feature files. infoPath = os.path.join(outPath, FONTINFO_FILENAME) if inPath == outPath: metaInfoPath = os.path.join(inPath, METAINFO_FILENAME) metaInfo = dict( creator="org.robofab.ufoLib", formatVersion=1 ) writePlistAtomically(metaInfo, metaInfoPath) writePlistAtomically(infoData, infoPath) featuresPath = os.path.join(inPath, FEATURES_FILENAME) if os.path.exists(featuresPath): os.remove(featuresPath) # otherwise write everything. else: writer = UFOWriter(outPath, formatVersion=1) writer.writeGroups(groups) writer.writeKerning(kerning) writer.writeLib(libData) # write the info manually writePlistAtomically(infoData, infoPath) # copy the glyph tree inGlyphs = os.path.join(inPath, GLYPHS_DIRNAME) outGlyphs = os.path.join(outPath, GLYPHS_DIRNAME) if os.path.exists(inGlyphs): shutil.copytree(inGlyphs, outGlyphs)
def testInfo(self): self.setUpFont(doInfo=True) otherResults = self.compareToUFO(doInfo=False) self.assertEqual(otherResults["kerning"], False) self.assertEqual(otherResults["groups"], False) self.assertEqual(otherResults["features"], False) self.assertEqual(otherResults["lib"], False) expectedPath = os.path.join(ufoPath2, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") expected = readPlist(expectedPath) written = readPlist(writtenPath) dummyFont = NewFont() _ufoToFLAttrMapping = dict(dummyFont.info._ufoToFLAttrMapping) dummyFont.close() for attr, expectedValue in expected.items(): # cheat by skipping attrs that aren't supported if _ufoToFLAttrMapping[attr]["nakedAttribute"] is None: continue self.assertEqual((attr, expectedValue), (attr, written[attr])) self.tearDownFont()
def __init__(self, fonts, glyphs, mode, callback): self.allGlyphs = set() for path, font in fonts.items(): if font is None: contentsPath = os.path.join(path, "glyphs", "contents.plist") if not os.path.exists(contentsPath): continue else: contents = readPlist(contentsPath) self.allGlyphs = self.allGlyphs | set(contents.keys()) else: self.allGlyphs = self.allGlyphs | set(font.keys()) if glyphs is None: self.selectedGlyphs = list(self.allGlyphs) self.selectedGlyphs.sort() self.unselectedGlyphs = [] else: self.selectedGlyphs = glyphs self.unselectedGlyphs = list(self.allGlyphs - set(glyphs)) self.unselectedGlyphs.sort() self.callback = callback mode = mode.title() self.w = dialogKit.ModalDialog((472, 400), "Glyphs", okCallback=self.okCallback) self.w.unselectedTitle = dialogKit.TextBox((12, 12, 150, 20), "Ignore:") self.w.unselectedGlyphsList = dialogKit.List((12, 37, 150, -60), self.unselectedGlyphs) self.w.addSelectionButton = dialogKit.Button( (172, 37, 130, 20), ">>>", callback=self.addSelectionCallback) self.w.removeSelectionButton = dialogKit.Button( (172, 67, 130, 20), "<<<", callback=self.removeSelectionCallback) self.w.addAllButton = dialogKit.Button((172, 97, 130, 20), "%s All" % mode, callback=self.addAllCallback) self.w.removeAllButton = dialogKit.Button( (172, 127, 130, 20), "Ignore All", callback=self.removeAllCallback) self.w.fromFontSelection = dialogKit.Button( (172, 157, 130, 20), "Font Selection", callback=self.fontSelectionCallback) self.w.selectedTitle = dialogKit.TextBox((310, 12, 150, 20), "%s:" % mode) self.w.selectedGlyphsList = dialogKit.List((310, 37, 150, -60), self.selectedGlyphs) self.w.open()
def readKerning(self): """ Read kerning.plist. Returns a dict. """ path = os.path.join(self._path, KERNING_FILENAME) if not self._checkForFile(path): return {} kerningNested = readPlist(path) kerning = {} for left in kerningNested: for right in kerningNested[left]: value = kerningNested[left][right] kerning[left, right] = value return kerning
def readMetaInfo(self): """ Read metainfo.plist. Only used for internal operations. """ path = os.path.join(self._path, METAINFO_FILENAME) if not self._checkForFile(path): raise UFOLibError("metainfo.plist is missing in %s. This file is required." % self._path) # should there be a blind try/except with a UFOLibError # raised in except here (and elsewhere)? It would be nice to # provide external callers with a single exception to catch. data = readPlist(path) formatVersion = data["formatVersion"] if formatVersion not in supportedUFOFormatVersions: raise UFOLibError("Unsupported UFO format (%d) in %s." % (formatVersion, self._path)) self._formatVersion = formatVersion
def readInfo(self, info): """ Read fontinfo.plist. It requires an object that allows setting attributes with names that follow the fontinfo.plist version 2 specification. This will write the attributes defined in the file into the object. """ # load the file and return if there is no file path = os.path.join(self._path, FONTINFO_FILENAME) if not self._checkForFile(path): return infoDict = readPlist(path) infoDataToSet = {} # version 1 if self._formatVersion == 1: for attr in fontInfoAttributesVersion1: value = infoDict.get(attr) if value is not None: infoDataToSet[attr] = value infoDataToSet = _convertFontInfoDataVersion1ToVersion2( infoDataToSet) # version 2 elif self._formatVersion == 2: for attr, dataValidationDict in _fontInfoAttributesVersion2ValueData.items( ): value = infoDict.get(attr) if value is None: continue infoDataToSet[attr] = value # unsupported version else: raise NotImplementedError # validate data infoDataToSet = _validateInfoVersion2Data(infoDataToSet) # populate the object for attr, value in infoDataToSet.items(): try: setattr(info, attr, value) except AttributeError: raise UFOLibError( "The supplied info object does not support setting a necessary attribute (%s)." % attr)
def __init__(self, fonts, glyphs, mode, callback): self.allGlyphs = set() for path, font in fonts.items(): if font is None: contentsPath = os.path.join(path, "glyphs", "contents.plist") if not os.path.exists(contentsPath): continue else: contents = readPlist(contentsPath) self.allGlyphs = self.allGlyphs | set(contents.keys()) else: self.allGlyphs = self.allGlyphs | set(font.keys()) if glyphs is None: self.selectedGlyphs = list(self.allGlyphs) self.selectedGlyphs.sort() self.unselectedGlyphs = [] else: self.selectedGlyphs = glyphs self.unselectedGlyphs = list(self.allGlyphs - set(glyphs)) self.unselectedGlyphs.sort() self.callback = callback mode = mode.title() self.w = dialogKit.ModalDialog((472, 400), "Glyphs", okCallback=self.okCallback) self.w.unselectedTitle = dialogKit.TextBox((12, 12, 150, 20), "Ignore:") self.w.unselectedGlyphsList = dialogKit.List((12, 37, 150, -60), self.unselectedGlyphs) self.w.addSelectionButton = dialogKit.Button((172, 37, 130, 20), ">>>", callback=self.addSelectionCallback) self.w.removeSelectionButton = dialogKit.Button((172, 67, 130, 20), "<<<", callback=self.removeSelectionCallback) self.w.addAllButton = dialogKit.Button((172, 97, 130, 20), "%s All" % mode, callback=self.addAllCallback) self.w.removeAllButton = dialogKit.Button((172, 127, 130, 20), "Ignore All", callback=self.removeAllCallback) self.w.fromFontSelection = dialogKit.Button((172, 157, 130, 20), "Font Selection", callback=self.fontSelectionCallback) self.w.selectedTitle = dialogKit.TextBox((310, 12, 150, 20), "%s:" % mode) self.w.selectedGlyphsList = dialogKit.List((310, 37, 150, -60), self.selectedGlyphs) self.w.open()
def readInfo(self, info): """ Read fontinfo.plist. It requires an object that allows setting attributes with names that follow the fontinfo.plist version 2 specification. This will write the attributes defined in the file into the object. """ # load the file and return if there is no file path = os.path.join(self._path, FONTINFO_FILENAME) if not self._checkForFile(path): return infoDict = readPlist(path) infoDataToSet = {} # version 1 if self._formatVersion == 1: for attr in fontInfoAttributesVersion1: value = infoDict.get(attr) if value is not None: infoDataToSet[attr] = value infoDataToSet = _convertFontInfoDataVersion1ToVersion2(infoDataToSet) # version 2 elif self._formatVersion == 2: for attr, dataValidationDict in _fontInfoAttributesVersion2ValueData.items(): value = infoDict.get(attr) if value is None: continue infoDataToSet[attr] = value # unsupported version else: raise NotImplementedError # validate data infoDataToSet = _validateInfoVersion2Data(infoDataToSet) # populate the object for attr, value in infoDataToSet.items(): try: setattr(info, attr, value) except AttributeError: raise UFOLibError("The supplied info object does not support setting a necessary attribute (%s)." % attr)
def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): readerExpected = UFOReader(ufoPath2) readerWritten = UFOReader(self.dstDir) results = {} if doInfo: matches = True expectedPath = os.path.join(ufoPath2, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") if not os.path.exists(writtenPath): matches = False else: dummyFont = NewFont() _ufoToFLAttrMapping = dict(dummyFont.info._ufoToFLAttrMapping) dummyFont.close() expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): # cheat by skipping attrs that aren't supported if _ufoToFLAttrMapping[attr]["nakedAttribute"] is None: continue if expectedValue != written[attr]: matches = False break results["info"] = matches if doKerning: matches = True expectedPath = os.path.join(ufoPath2, "kerning.plist") writtenPath = os.path.join(self.dstDir, "kerning.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["kerning"] = matches if doGroups: matches = True expectedPath = os.path.join(ufoPath2, "groups.plist") writtenPath = os.path.join(self.dstDir, "groups.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["groups"] = matches if doFeatures: matches = True expectedPath = os.path.join(ufoPath2, "features.fea") writtenPath = os.path.join(self.dstDir, "features.fea") if not os.path.exists(writtenPath): matches = False else: f = open(expectedPath, "r") expectedText = f.read() f.close() f = open(writtenPath, "r") writtenText = f.read() f.close() # FontLab likes to add lines to the features, so skip blank lines. expectedText = [ line for line in expectedText.splitlines() if line ] writtenText = [ line for line in writtenText.splitlines() if line ] matches = "\n".join(expectedText) == "\n".join(writtenText) results["features"] = matches if doLib: matches = True expectedPath = os.path.join(ufoPath2, "lib.plist") writtenPath = os.path.join(self.dstDir, "lib.plist") if not os.path.exists(writtenPath): matches = False else: # the test file doesn't have the glyph order # so purge it from the written writtenLib = readPlist(writtenPath) del writtenLib["org.robofab.glyphOrder"] matches = readPlist(expectedPath) == writtenLib results["lib"] = matches return results
def importUFO(ufoPath, newFile=True, saveFile=True, closeFile=True, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True, doHints=False, doMarks=True, doMasks=True, glyphs=None): # get the VFB path vfbPath = os.path.splitext(ufoPath)[0] + ".vfb" if not newFile: font = None for font in AllFonts(): if font.path == vfbPath: break if font is None: if not os.path.exists(vfbPath): Message("Could not find the FontLab file \"%s\"." % os.path.basename(vfbPath)) return font = OpenFont(vfbPath) else: if saveFile: if os.path.exists(vfbPath): vfbPath = _findAvailablePathName(vfbPath) font = NewFont() # make the font the top font in FL fl.ifont = font.fontIndex # read the UFO font.readUFO(ufoPath, doHints=doHints, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, doLib=doLib, doFeatures=doFeatures, glyphs=glyphs) # load the masks and marks if doMasks or doMarks: for glyph in font: lib = glyph.lib if doMarks: if lib.has_key(MARK_LIB_KEY): glyph.mark = lib[MARK_LIB_KEY] del lib[MARK_LIB_KEY] if doMasks: if lib.has_key(MASK_LIB_KEY): # open a glyph window fl.EditGlyph(glyph.index) # switch to the mask layer fl.CallCommand(fl_cmd.ViewEditMask) # add the mask data instructions = lib[MASK_LIB_KEY] pen = glyph.getPointPen() instructionsDrawPoints(instructions, pen) # switch back to the edit layer fl.CallCommand(fl_cmd.ViewEditMask) # clear the mask data from the glyph lib del lib[MASK_LIB_KEY] # close all glyph windows. sometimes this actually works. fl.CallCommand(fl_cmd.WindowCloseAllGlyphWindows) # load the WWS names if doInfo: info = readPlist(os.path.join(ufoPath, "fontInfo.plist")) if "openTypeNameWWSFamilyName" in info: font.lib[WWS_FAMILY_KEY] = info["openTypeNameWWSFamilyName"] elif "openTypeNameWWSFamilyName" in font.lib: del font.lib[WWS_FAMILY_KEY] if "openTypeNameWWSSubfamilyName" in info: font.lib[WWS_SUBFAMILY_KEY] = info["openTypeNameWWSSubfamilyName"] elif "openTypeNameWWSSubfamilyName" in font.lib: del font.lib[WWS_SUBFAMILY_KEY] # update the font font.update() # save and close if saveFile: font.save(vfbPath) if closeFile: font.close()
def exportUFO(font, newFile=True, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True, doHints=False, doMarks=True, doMasks=True, glyphs=None, formatVersion=2): # get the UFO path ufoPath = os.path.splitext(font.path)[0] + ".ufo" if not newFile: if not os.path.exists(ufoPath): Message("Could not find the UFO file \"%s\"." % os.path.basename(ufoPath)) return else: if os.path.exists(ufoPath): ufoPath = _findAvailablePathName(ufoPath) # make sure no bogus glyph names are coming in if glyphs is not None: glyphs = [glyphName for glyphName in glyphs if font.has_key(glyphName)] # make the font the top font in FL fl.ifont = font.fontIndex # add the masks and marks to the glyph.lib if doMasks or doMarks: if glyphs is None: glyphNames = font.keys() else: glyphNames = glyphs for glyphName in glyphNames: glyph = font[glyphName] if doMarks: mark = glyph.mark glyph.lib[MARK_LIB_KEY] = mark if doMasks: # open a glyph window fl.EditGlyph(glyph.index) # switch to the mask layer fl.CallCommand(fl_cmd.ViewEditMask) # if the mask is empty, skip this step if not len(glyph): # switch back to the edit layer fl.CallCommand(fl_cmd.ViewEditMask) continue # get the mask data pen = InstructionPointPen() glyph.drawPoints(pen) # switch back to the edit layer fl.CallCommand(fl_cmd.ViewEditMask) # write the mask data to the glyph lib instructions = pen.getInstructions() if instructions: glyph.lib[MASK_LIB_KEY] = instructions # close all glyph windows. sometimes this actually works. fl.CallCommand(fl_cmd.WindowCloseAllGlyphWindows) # remove WWS names from the lib wwsStorage = {} if "openTypeNameWWSFamilyName" in font.lib: wwsStorage["openTypeNameWWSFamilyName"] = font.lib.pop(WWS_FAMILY_KEY) if "openTypeNameWWSSubfamilyName" in font.lib: wwsStorage["openTypeNameWWSSubfamilyName"] = font.lib.pop( WWS_SUBFAMILY_KEY) # write the UFO font.writeUFO(path=ufoPath, doHints=doHints, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, doLib=doLib, doFeatures=doFeatures, glyphs=glyphs, formatVersion=formatVersion) # add the WWS names to the info if doInfo: infoPath = os.path.join(ufoPath, "fontinfo.plist") info = readPlist(infoPath) newInfo = deepcopy(info) newInfo.update(wwsStorage) if info != newInfo: writePlist(newInfo, infoPath) # put the WWS names back in the lib font.lib.update(wwsStorage) # remove the masks and marks from the glyph.lib if doMasks or doMarks: if glyphs is None: glyphNames = font.keys() else: glyphNames = glyphs for glyphName in glyphNames: glyph = font[glyphName] lib = glyph.lib if lib.has_key(MASK_LIB_KEY): del lib[MASK_LIB_KEY] if lib.has_key(MARK_LIB_KEY): del lib[MARK_LIB_KEY]
""" This implements the PlistLib Writer for python < 2.2. Deconstructed from Just van Rossums's plistlib.py (I apoligise!), but without the 2.3 python dependencies, so it can be used in elderly programs with elderly embedded pythons. This produces a plist file with macroman encoding as the whole unicode schtick doesn't exist in 1.5.2. For comments and notes on how to use this module, please have a look at the original plistlib.py. Supported: string integer dictionary list tuple Not supported: binary data, uses base64 which might be available, I'll add it when I need it. dates: uses xml.utils.iso8601 I'll add it when I need it. """ import string import sys from types import StringType, IntType, FloatType, ListType, TupleType, DictType FogPlistWriterError = "FogPlistWriterError" PLISTHEADER = """\ <?xml version="1.0" encoding="macroman"?>
def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): readerExpected = UFOReader(ufoPath1) readerWritten = UFOReader(self.dstDir) results = {} if doInfo: matches = True expectedPath = os.path.join(ufoPath1, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") if not os.path.exists(writtenPath): matches = False else: expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): if expectedValue != written[attr]: matches = False break results["info"] = matches if doKerning: matches = True expectedPath = os.path.join(ufoPath1, "kerning.plist") writtenPath = os.path.join(self.dstDir, "kerning.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["kerning"] = matches if doGroups: matches = True expectedPath = os.path.join(ufoPath1, "groups.plist") writtenPath = os.path.join(self.dstDir, "groups.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["groups"] = matches if doFeatures: matches = True featuresPath = os.path.join(self.dstDir, "features.fea") libPath = os.path.join(self.dstDir, "lib.plist") if os.path.exists(featuresPath): matches = False else: fontLib = readPlist(libPath) writtenText = [fontLib.get("org.robofab.opentype.classes", "")] features = fontLib.get("org.robofab.opentype.features", {}) featureOrder = fontLib.get("org.robofab.opentype.featureorder", []) for featureName in featureOrder: writtenText.append(features.get(featureName, "")) writtenText = "\n".join(writtenText) # FontLab likes to add lines to the features, so skip blank lines. expectedText = [ line for line in expectedFormatVersion1Features.splitlines() if line ] writtenText = [ line for line in writtenText.splitlines() if line ] matches = "\n".join(expectedText) == "\n".join(writtenText) results["features"] = matches if doLib: matches = True expectedPath = os.path.join(ufoPath1, "lib.plist") writtenPath = os.path.join(self.dstDir, "lib.plist") if not os.path.exists(writtenPath): matches = False else: # the test file doesn't have the glyph order # so purge it from the written writtenLib = readPlist(writtenPath) del writtenLib["org.robofab.glyphOrder"] matches = readPlist(expectedPath) == writtenLib results["lib"] = matches return results
def exportUFO(font, newFile=True, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True, doHints=False, doMarks=True, doMasks=True, glyphs=None, formatVersion=2): # get the UFO path ufoPath = os.path.splitext(font.path)[0] + ".ufo" if not newFile: if not os.path.exists(ufoPath): Message("Could not find the UFO file \"%s\"." % os.path.basename(ufoPath)) return else: if os.path.exists(ufoPath): ufoPath = _findAvailablePathName(ufoPath) # make sure no bogus glyph names are coming in if glyphs is not None: glyphs = [glyphName for glyphName in glyphs if font.has_key(glyphName)] # make the font the top font in FL fl.ifont = font.fontIndex # add the masks and marks to the glyph.lib if doMasks or doMarks: if glyphs is None: glyphNames = font.keys() else: glyphNames = glyphs for glyphName in glyphNames: glyph = font[glyphName] if doMarks: mark = glyph.mark glyph.lib[MARK_LIB_KEY] = mark if doMasks: # open a glyph window fl.EditGlyph(glyph.index) # switch to the mask layer fl.CallCommand(fl_cmd.ViewEditMask) # if the mask is empty, skip this step if not len(glyph): # switch back to the edit layer fl.CallCommand(fl_cmd.ViewEditMask) continue # get the mask data pen = InstructionPointPen() glyph.drawPoints(pen) # switch back to the edit layer fl.CallCommand(fl_cmd.ViewEditMask) # write the mask data to the glyph lib instructions = pen.getInstructions() if instructions: glyph.lib[MASK_LIB_KEY] = instructions # close all glyph windows. sometimes this actually works. fl.CallCommand(fl_cmd.WindowCloseAllGlyphWindows) # remove WWS names from the lib wwsStorage = {} if "openTypeNameWWSFamilyName" in font.lib: wwsStorage["openTypeNameWWSFamilyName"] = font.lib.pop(WWS_FAMILY_KEY) if "openTypeNameWWSSubfamilyName" in font.lib: wwsStorage["openTypeNameWWSSubfamilyName"] = font.lib.pop(WWS_SUBFAMILY_KEY) # write the UFO font.writeUFO(path=ufoPath, doHints=doHints, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, doLib=doLib, doFeatures=doFeatures, glyphs=glyphs, formatVersion=formatVersion) # add the WWS names to the info if doInfo: infoPath = os.path.join(ufoPath, "fontinfo.plist") info = readPlist(infoPath) newInfo = deepcopy(info) newInfo.update(wwsStorage) if info != newInfo: writePlist(newInfo, infoPath) # put the WWS names back in the lib font.lib.update(wwsStorage) # remove the masks and marks from the glyph.lib if doMasks or doMarks: if glyphs is None: glyphNames = font.keys() else: glyphNames = glyphs for glyphName in glyphNames: glyph = font[glyphName] lib = glyph.lib if lib.has_key(MASK_LIB_KEY): del lib[MASK_LIB_KEY] if lib.has_key(MARK_LIB_KEY): del lib[MARK_LIB_KEY]
def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): readerExpected = UFOReader(ufoPath2) readerWritten = UFOReader(self.dstDir) results = {} if doInfo: matches = True expectedPath = os.path.join(ufoPath2, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") if not os.path.exists(writtenPath): matches = False else: dummyFont = NewFont() _ufoToFLAttrMapping = dict(dummyFont.info._ufoToFLAttrMapping) dummyFont.close() expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): # cheat by skipping attrs that aren't supported if _ufoToFLAttrMapping[attr]["nakedAttribute"] is None: continue if expectedValue != written[attr]: matches = False break results["info"] = matches if doKerning: matches = True expectedPath = os.path.join(ufoPath2, "kerning.plist") writtenPath = os.path.join(self.dstDir, "kerning.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["kerning"] = matches if doGroups: matches = True expectedPath = os.path.join(ufoPath2, "groups.plist") writtenPath = os.path.join(self.dstDir, "groups.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["groups"] = matches if doFeatures: matches = True expectedPath = os.path.join(ufoPath2, "features.fea") writtenPath = os.path.join(self.dstDir, "features.fea") if not os.path.exists(writtenPath): matches = False else: f = open(expectedPath, "r") expectedText = f.read() f.close() f = open(writtenPath, "r") writtenText = f.read() f.close() # FontLab likes to add lines to the features, so skip blank lines. expectedText = [line for line in expectedText.splitlines() if line] writtenText = [line for line in writtenText.splitlines() if line] matches = "\n".join(expectedText) == "\n".join(writtenText) results["features"] = matches if doLib: matches = True expectedPath = os.path.join(ufoPath2, "lib.plist") writtenPath = os.path.join(self.dstDir, "lib.plist") if not os.path.exists(writtenPath): matches = False else: # the test file doesn't have the glyph order # so purge it from the written writtenLib = readPlist(writtenPath) del writtenLib["org.robofab.glyphOrder"] matches = readPlist(expectedPath) == writtenLib results["lib"] = matches return results
def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): readerExpected = UFOReader(ufoPath1) readerWritten = UFOReader(self.dstDir) results = {} if doInfo: matches = True expectedPath = os.path.join(ufoPath1, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") if not os.path.exists(writtenPath): matches = False else: expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): if expectedValue != written[attr]: matches = False break results["info"] = matches if doKerning: matches = True expectedPath = os.path.join(ufoPath1, "kerning.plist") writtenPath = os.path.join(self.dstDir, "kerning.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["kerning"] = matches if doGroups: matches = True expectedPath = os.path.join(ufoPath1, "groups.plist") writtenPath = os.path.join(self.dstDir, "groups.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["groups"] = matches if doFeatures: matches = True featuresPath = os.path.join(self.dstDir, "features.fea") libPath = os.path.join(self.dstDir, "lib.plist") if os.path.exists(featuresPath): matches = False else: fontLib = readPlist(libPath) writtenText = [fontLib.get("org.robofab.opentype.classes", "")] features = fontLib.get("org.robofab.opentype.features", {}) featureOrder= fontLib.get("org.robofab.opentype.featureorder", []) for featureName in featureOrder: writtenText.append(features.get(featureName, "")) writtenText = "\n".join(writtenText) # FontLab likes to add lines to the features, so skip blank lines. expectedText = [line for line in expectedFormatVersion1Features.splitlines() if line] writtenText = [line for line in writtenText.splitlines() if line] matches = "\n".join(expectedText) == "\n".join(writtenText) results["features"] = matches if doLib: matches = True expectedPath = os.path.join(ufoPath1, "lib.plist") writtenPath = os.path.join(self.dstDir, "lib.plist") if not os.path.exists(writtenPath): matches = False else: # the test file doesn't have the glyph order # so purge it from the written writtenLib = readPlist(writtenPath) del writtenLib["org.robofab.glyphOrder"] matches = readPlist(expectedPath) == writtenLib results["lib"] = matches return results
def compareToUFO(self): readerExpected = UFOReader(ufoPath2) readerWritten = UFOReader(self.dstDir) results = {} # info matches = True expectedPath = os.path.join(ufoPath2, "fontinfo.plist") writtenPath = os.path.join(self.dstDir, "fontinfo.plist") if not os.path.exists(writtenPath): matches = False else: expected = readPlist(expectedPath) written = readPlist(writtenPath) for attr, expectedValue in expected.items(): if expectedValue != written[attr]: matches = False break results["info"] = matches # kerning matches = True expectedPath = os.path.join(ufoPath2, "kerning.plist") writtenPath = os.path.join(self.dstDir, "kerning.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["kerning"] = matches # groups matches = True expectedPath = os.path.join(ufoPath2, "groups.plist") writtenPath = os.path.join(self.dstDir, "groups.plist") if not os.path.exists(writtenPath): matches = False else: matches = readPlist(expectedPath) == readPlist(writtenPath) results["groups"] = matches # features matches = True expectedPath = os.path.join(ufoPath2, "features.fea") writtenPath = os.path.join(self.dstDir, "features.fea") if not os.path.exists(writtenPath): matches = False else: f = open(expectedPath, "r") expectedText = f.read() f.close() f = open(writtenPath, "r") writtenText = f.read() f.close() # FontLab likes to add lines to the features, so skip blank lines. expectedText = [line for line in expectedText.splitlines() if line] writtenText = [line for line in writtenText.splitlines() if line] matches = "\n".join(expectedText) == "\n".join(writtenText) results["features"] = matches # lib matches = True expectedPath = os.path.join(ufoPath2, "lib.plist") writtenPath = os.path.join(self.dstDir, "lib.plist") if not os.path.exists(writtenPath): matches = False else: writtenLib = readPlist(writtenPath) matches = readPlist(expectedPath) == writtenLib results["lib"] = matches return results