def run(args): options = Options(args) # Set the current dir to the design space dir, so that relative paths in # the design space file will work. dsDir,dsFile = os.path.split(os.path.abspath(options.dsPath)) os.chdir(dsDir) options.dsPath = dsFile dsPath, newInstancesList = readDesignSpaceFile(options) if not dsPath: return version = 2 if len(newInstancesList) == 1: logMsg.log( "Building 1 instance..") else: logMsg.log("Building %s instances.." % (len(newInstancesList))) mutatorMathBuild(documentPath=dsPath, outputUFOFormatVersion=version, roundGeometry=(not options.allowDecimalCoords)) if (dsPath != options.dsPath) and os.path.exists(dsPath): os.remove(dsPath) logMsg.log("Built %s instances.." % (len(newInstancesList))) if options.doAutoHint or options.doOverlapRemoval: logMsg.log( "Applying post-processing") # Apply autohint and checkoutlines, if requested. for instancePath in newInstancesList: # make new instance font. updateInstance(options, instancePath) if not options.doOverlapRemoval: # checkOutlinesUFO does ufoTools.validateLayers() for instancePath in newInstancesList: # make sure that that there are no old glyphs left in the processed glyphs folder. ufoTools.validateLayers(instancePath)
def open(self, use_hash_map): font_path = self.font_path try: ufoTools.validateLayers(font_path) self.defcon_font = defcon.Font(font_path) self.ufo_format = self.defcon_font.ufoFormatVersion if self.ufo_format < 2: self.ufo_format = 2 self.font_type = UFO_FONT_TYPE self.use_hash_map = use_hash_map self.ufo_font_hash_data = ufoTools.UFOFontData( font_path, self.use_hash_map, programName=ufoTools.kCheckOutlineName) self.ufo_font_hash_data.readHashMap() except ufoLib.UFOLibError as e: if (not os.path.isdir(font_path)) \ and "metainfo.plist is missing" in e.message: # It was a file, but not a UFO font. # Try converting to UFO font, and try again. print("converting to temp UFO font...") self.temp_ufo_path = temp_path = font_path + ".temp.ufo" if os.path.exists(temp_path): shutil.rmtree(temp_path) cmd = "tx -ufo \"%s\" \"%s\"" % (font_path, temp_path) subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if os.path.exists(temp_path): try: self.defcon_font = defcon.Font(temp_path) except ufoLib.UFOLibError: return # It must be a font file! self.temp_ufo_path = temp_path # figure out font type. try: ff = open(font_path, "rb") data = ff.read(10) ff.close() except (IOError, OSError): return if data[:4] == "OTTO": # it is an OTF font. self.font_type = OPENTYPE_CFF_FONT_TYPE elif (data[0] == '\1') and (data[1] == '\0'): # CFF file self.font_type = CFF_FONT_TYPE elif "%" in data: self.font_type = TYPE1_FONT_TYPE else: print('Font type is unknown: ' 'will not be able to save changes') else: raise e return self.defcon_font
def run(args): options = Options(args) # Set the current dir to the design space dir, so that relative paths in # the design space file will work. dsDir, dsFile = os.path.split(os.path.abspath(options.dsPath)) os.chdir(dsDir) options.dsPath = dsFile dsPath, newInstancesList = readDesignSpaceFile(options) if not dsPath: return version = 2 if len(newInstancesList) == 1: logMsg.log("Building 1 instance...") else: logMsg.log("Building %s instances..." % (len(newInstancesList))) mutatorMathBuild(documentPath=dsPath, outputUFOFormatVersion=version, roundGeometry=(not options.allowDecimalCoords)) if (dsPath != options.dsPath) and os.path.exists(dsPath): os.remove(dsPath) logMsg.log("Built %s instances." % (len(newInstancesList))) # Remove glyph.lib and font.lib (except for "public.glyphOrder") for instancePath in newInstancesList: postProcessInstance(instancePath, options) if options.doNormalize and haveUfONormalizer: logMsg.log("Applying UFO normalization...") for instancePath in newInstancesList: ufonormalizer.normalizeUFO(instancePath, outputPath=None, onlyModified=True, writeModTimes=False) if options.doAutoHint or options.doOverlapRemoval: logMsg.log("Applying post-processing...") # Apply autohint and checkoutlines, if requested. for instancePath in newInstancesList: # make new instance font. updateInstance(options, instancePath) if not options.doOverlapRemoval: # checkOutlinesUFO does ufoTools.validateLayers() for instancePath in newInstancesList: # make sure that that there are no old glyphs left in the processed glyphs folder. ufoTools.validateLayers(instancePath) if options.doOverlapRemoval or options.doAutoHint: # The defcon library renames glyphs. Need to fix them again. for instancePath in newInstancesList: if haveUfONormalizer and options.doNormalize: ufonormalizer.normalizeUFO(instancePath, outputPath=None, onlyModified=False, writeModTimes=False)
def open(self, useHashMap): fontPath = self.fontPath try: ufoTools.validateLayers(fontPath) self.dFont = dFont = defcon.Font(fontPath) self.ufoFormat = dFont.ufoFormatVersion if self.ufoFormat < 2: self.ufoFormat = 2 self.fontType = kUFOFontType self.useHashMap = useHashMap self.ufoFontHashData = ufoTools.UFOFontData( fontPath, self.useHashMap, programName=ufoTools.kCheckOutlineName) self.ufoFontHashData.readHashMap() except ufoLib.UFOLibError, e: if (not os.path.isdir(fontPath) ) and "metainfo.plist is missing" in e.message: # It was a file, but not a UFO font. try converting to UFO font, and try again. print "converting to temp UFO font..." self.tempUFOPath = tempPath = fontPath + ".temp.ufo" if os.path.exists(tempPath): shutil.rmtree(tempPath) cmd = "tx -ufo \"%s\" \"%s\"" % (fontPath, tempPath) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout log = p.read() if os.path.exists(tempPath): try: self.dFont = dFont = defcon.Font(tempPath) except ufoLib.UFOLibError, e: return # It must be a font file! self.tempUFOPath = tempPath # figure out font type. try: ff = file(fontPath, "rb") data = ff.read(10) ff.close() except (IOError, OSError): return if data[:4] == "OTTO": # it is an OTF font. self.fontType = kOpenTypeCFFFontType elif (data[0] == '\1') and (data[1] == '\0'): # CFF file self.fontType = kCFFFontType elif "%" in data: self.fontType = kType1FontType else: print "Font type is unknown: will not be able to save changes"
def run(args): options = Options(args) # Set the current dir to the design space dir, so that relative paths in # the design space file will work. dsDir,dsFile = os.path.split(os.path.abspath(options.dsPath)) os.chdir(dsDir) options.dsPath = dsFile dsPath, newInstancesList = readDesignSpaceFile(options) if not dsPath: return version = 2 if len(newInstancesList) == 1: logMsg.log("Building 1 instance...") else: logMsg.log("Building %s instances..." % (len(newInstancesList))) mutatorMathBuild(documentPath=dsPath, outputUFOFormatVersion=version, roundGeometry=(not options.allowDecimalCoords)) if (dsPath != options.dsPath) and os.path.exists(dsPath): os.remove(dsPath) logMsg.log("Built %s instances." % (len(newInstancesList))) # Remove glyph.lib and font.lib (except for "public.glyphOrder") for instancePath in newInstancesList: clearCustomLibs(instancePath) if options.doNormalize: logMsg.log("Applying UFO normalization...") for instancePath in newInstancesList: if haveUfONormalizer: ufonormalizerLib.normalizeUFO(instancePath, outputPath=None, onlyModified=True) if options.doAutoHint or options.doOverlapRemoval: logMsg.log("Applying post-processing...") # Apply autohint and checkoutlines, if requested. for instancePath in newInstancesList: # make new instance font. updateInstance(options, instancePath) if not options.doOverlapRemoval: # checkOutlinesUFO does ufoTools.validateLayers() for instancePath in newInstancesList: # make sure that that there are no old glyphs left in the processed glyphs folder. ufoTools.validateLayers(instancePath) if options.doOverlapRemoval or options.doAutoHint: # The defcon library renames glyphs. Need to fix them again. for instancePath in newInstancesList: if haveUfONormalizer and options.doNormalize: ufonormalizerLib.normalizeUFO(instancePath, outputPath=None, onlyModified=False)
def open(self, useHashMap): fontPath = self.fontPath try: ufoTools.validateLayers(fontPath) self.dFont = dFont = defcon.Font(fontPath) self.ufoFormat = dFont.ufoFormatVersion if self.ufoFormat < 2: self.ufoFormat = 2 self.fontType = kUFOFontType self.useHashMap = useHashMap self.ufoFontHashData = ufoTools.UFOFontData(fontPath, self.useHashMap, programName=ufoTools.kCheckOutlineName) self.ufoFontHashData.readHashMap() except ufoLib.UFOLibError,e: if (not os.path.isdir(fontPath)) and "metainfo.plist is missing" in e.message: # It was a file, but not a UFO font. try converting to UFO font, and try again. print "converting to temp UFO font..." self.tempUFOPath = tempPath = fontPath + ".temp.ufo" if os.path.exists(tempPath): shutil.rmtree(tempPath) cmd = "tx -ufo \"%s\" \"%s\"" % (fontPath, tempPath) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout log = p.read() if os.path.exists(tempPath): try: self.dFont = dFont = defcon.Font(tempPath) except ufoLib.UFOLibError,e: return # It must be a font file! self.tempUFOPath = tempPath # figure out font type. try: ff = file(fontPath, "rb") data = ff.read(10) ff.close() except (IOError, OSError): return if data[:4] == "OTTO": # it is an OTF font. self.fontType = kOpenTypeCFFFontType elif (data[0] == '\1') and (data[1] == '\0'): # CFF file self.fontType = kCFFFontType elif "%" in data: self.fontType = kType1FontType else: print "Font type is unknown: will not be able to save changes"
def run(args): options = Options(args) # Set the current dir to the design space dir, so that relative paths in # the design space file will work. dsDir, dsFile = os.path.split(os.path.abspath(options.dsPath)) os.chdir(dsDir) options.dsPath = dsFile dsPath, newInstancesList = readDesignSpaceFile(options) if not dsPath: return version = 2 if len(newInstancesList) == 1: logMsg.log("Building 1 instance..") else: logMsg.log("Building %s instances.." % (len(newInstancesList))) mutatorMathBuild(documentPath=dsPath, outputUFOFormatVersion=version, roundGeometry=(not options.allowDecimalCoords)) if (dsPath != options.dsPath) and os.path.exists(dsPath): os.remove(dsPath) logMsg.log("Built %s instances.." % (len(newInstancesList))) if options.doAutoHint or options.doOverlapRemoval: logMsg.log("Applying post-processing") # Apply autohint and checkoutlines, if requested. for instancePath in newInstancesList: # make new instance font. updateInstance(options, instancePath) if not options.doOverlapRemoval: # checkOutlinesUFO does ufoTools.validateLayers() for instancePath in newInstancesList: # make sure that that there are no old glyphs left in the processed glyphs folder. ufoTools.validateLayers(instancePath)
def run(args): options = getOptions() fontPath = os.path.abspath(options.filePath) dFont = None fontFile = FontFile(fontPath) dFont = fontFile.open(options.allowChanges) # We allow use of a hash map to skip glyphs only if fixing glyphs if options.clearHashMap: fontFile.clearHashMap() return if dFont == None: print "Could not open file: %s." % (fontPath) return glyphCount = len(dFont) changed = 0 glyphList = filterGlyphList(options, dFont.keys(), options.filePath) if not glyphList: raise focusFontError("Error: selected glyph list is empty for font <%s>." % options.filePath) if not options.writeToDefaultLayer: try: processedLayer = dFont.layers[kProcessedGlyphsLayerName] except KeyError: processedLayer = dFont.newLayer(kProcessedGlyphsLayerName) else: processedLayer = None fontFile.saveToDefaultLayer = 1 fontChanged = 0 lastHadMsg = 0 seenGlyphCount = 0 processedGlyphCount = 0 glyphList.sort() for glyphName in glyphList: changed = 0 seenGlyphCount +=1 msg = [] # fontFile.checkSkipGlyph updates the hash map for the glyph, so we call it even when # the '-all' option is used. skip = fontFile.checkSkipGlyph(glyphName, options.checkAll) #Note: this will delete glyphs from the processed layer, if the glyph hash has changed. if skip: continue processedGlyphCount += 1 dGlyph = dFont[glyphName] if dGlyph.components: dGlyph.decomposeAllComponents() newGlyph = booleanOperations.booleanGlyph.BooleanGlyph(dGlyph) glyphDigest = None for test in options.testList: if test != None: newGlyph, glyphDigest, changed, msg = test(newGlyph, glyphDigest, changed, msg, options) if len(msg) == 0: if lastHadMsg: print print ".", lastHadMsg = 0 else: print os.linesep + glyphName, " ".join(msg), if changed and options.allowChanges: fontChanged = 1 lastHadMsg = 1 if changed and options.allowChanges: originalContours = list(dGlyph) fontFile.updateHashEntry(glyphName, changed) if options.writeToDefaultLayer: fixedGlyph = dGlyph fixedGlyph.clearContours() else: processedLayer.newGlyph(glyphName) # will replace any pre-existing glyph fixedGlyph = processedLayer[glyphName] fixedGlyph.width = dGlyph.width fixedGlyph.height = dGlyph.height fixedGlyph.unicodes = dGlyph.unicodes pointPen = fixedGlyph.getPointPen() newGlyph.drawPoints(pointPen) if options.allowDecimalCoords: for contour in fixedGlyph: for point in contour: point.x = round(point.x, 3) point.y = round(point.y, 3) else: for contour in fixedGlyph: for point in contour: point.x = int(round(point.x)) point.y = int(round(point.y)) restoreContourOrder(fixedGlyph, originalContours) sys.stdout.flush() # Needed when the script is called from another script with Popen(). # update layer plist: the hash check call may have deleted processed layer glyphs because the default layer glyph is newer. # At this point, we may have deleted glyphs in the processed layer.writer.getGlyphSet() # will fail unless we update the contents.plist file to match. if options.allowChanges: ufoTools.validateLayers(fontPath, False) if not fontChanged: print fontFile.close() # Even if the program didn't change any glyphs, we should still save updates to the src glyph hash file. else: print fontFile.save() if processedGlyphCount != seenGlyphCount: print "Skipped %s of %s glyphs." % (seenGlyphCount - processedGlyphCount, seenGlyphCount) print "Done with font" return
def run(args): options = getOptions(args) fontPath = os.path.abspath(options.filePath) dFont = None fontFile = FontFile(fontPath) dFont = fontFile.open( options.allowChanges ) # We allow use of a hash map to skip glyphs only if fixing glyphs if options.clearHashMap: fontFile.clearHashMap() return if dFont == None: print "Could not open file: %s." % (fontPath) return glyphCount = len(dFont) changed = 0 glyphList = filterGlyphList(options, dFont.keys(), options.filePath) if not glyphList: raise focusFontError( "Error: selected glyph list is empty for font <%s>." % options.filePath) if not options.writeToDefaultLayer: try: processedLayer = dFont.layers[kProcessedGlyphsLayerName] except KeyError: processedLayer = dFont.newLayer(kProcessedGlyphsLayerName) else: processedLayer = None fontFile.saveToDefaultLayer = 1 fontChanged = 0 lastHadMsg = 0 seenGlyphCount = 0 processedGlyphCount = 0 glyphList.sort() for glyphName in glyphList: changed = 0 seenGlyphCount += 1 msg = [] # fontFile.checkSkipGlyph updates the hash map for the glyph, so we call it even when # the '-all' option is used. skip = fontFile.checkSkipGlyph(glyphName, options.checkAll) #Note: this will delete glyphs from the processed layer, if the glyph hash has changed. if skip: continue processedGlyphCount += 1 dGlyph = dFont[glyphName] if dGlyph.components: dGlyph.decomposeAllComponents() newGlyph = booleanOperations.booleanGlyph.BooleanGlyph(dGlyph) glyphDigest = None for test in options.testList: if test != None: newGlyph, glyphDigest, changed, msg = test( newGlyph, glyphDigest, changed, msg, options) if not options.quietMode: if len(msg) == 0: if lastHadMsg: print print ".", lastHadMsg = 0 else: print os.linesep + glyphName, " ".join(msg), lastHadMsg = 1 if changed and options.allowChanges: fontChanged = 1 originalContours = list(dGlyph) fontFile.updateHashEntry(glyphName, changed) if options.writeToDefaultLayer: fixedGlyph = dGlyph fixedGlyph.clearContours() else: processedLayer.newGlyph( glyphName) # will replace any pre-existing glyph fixedGlyph = processedLayer[glyphName] fixedGlyph.width = dGlyph.width fixedGlyph.height = dGlyph.height fixedGlyph.unicodes = dGlyph.unicodes pointPen = fixedGlyph.getPointPen() newGlyph.drawPoints(pointPen) if options.allowDecimalCoords: for contour in fixedGlyph: for point in contour: point.x = round(point.x, 3) point.y = round(point.y, 3) else: for contour in fixedGlyph: for point in contour: point.x = int(round(point.x)) point.y = int(round(point.y)) restoreContourOrder(fixedGlyph, originalContours) sys.stdout.flush( ) # Needed when the script is called from another script with Popen(). # update layer plist: the hash check call may have deleted processed layer glyphs because the default layer glyph is newer. # At this point, we may have deleted glyphs in the processed layer.writer.getGlyphSet() # will fail unless we update the contents.plist file to match. if options.allowChanges: ufoTools.validateLayers(fontPath, False) if not fontChanged: print fontFile.close( ) # Even if the program didn't change any glyphs, we should still save updates to the src glyph hash file. else: print fontFile.save() if processedGlyphCount != seenGlyphCount: print "Skipped %s of %s glyphs." % ( seenGlyphCount - processedGlyphCount, seenGlyphCount) print "Done with font" return
def run(args=None): options = get_options(args) font_path = os.path.abspath(options.file_path) font_file = FontFile(font_path) defcon_font = font_file.open(options.allow_changes) # We allow use of a hash map to skip glyphs only if fixing glyphs if options.clear_hash_map: font_file.clear_hash_map() return if defcon_font is None: print("Could not open file: %s." % font_path) return if not options.glyph_list: glyph_list = list(defcon_font.keys()) else: if not defcon_font.glyphOrder: raise FocusFontError( "Error: public.glyphOrder is empty or missing " "from lib.plist file of %s" % os.path.abspath(options.file_path)) else: glyph_list = filter_glyph_list(options.glyph_list, defcon_font.glyphOrder, options.file_path) if not glyph_list: raise FocusFontError( "Error: selected glyph list is empty for font <%s>." % options.file_path) if not options.write_to_default_layer: try: processed_layer = defcon_font.layers[PROCD_GLYPHS_LAYER_NAME] except KeyError: processed_layer = defcon_font.newLayer(PROCD_GLYPHS_LAYER_NAME) else: processed_layer = None font_file.save_to_default_layer = True font_changed = False last_had_msg = False seen_glyph_count = 0 processed_glyph_count = 0 for glyph_name in sorted(glyph_list): changed = False seen_glyph_count += 1 msg = [] if glyph_name not in defcon_font: continue # font_file.check_skip_glyph updates the hash map for the glyph, # so we call it even when the '-all' option is used. skip = font_file.check_skip_glyph(glyph_name, options.check_all) # Note: this will delete glyphs from the processed layer, # if the glyph hash has changed. if skip: continue processed_glyph_count += 1 defcon_glyph = defcon_font[glyph_name] if defcon_glyph.components: defcon_glyph.decomposeAllComponents() new_glyph = booleanOperations.booleanGlyph.BooleanGlyph(defcon_glyph) if len(new_glyph) == 0: # Complain about empty glyph only if it is not a space glyph. if not RE_SPACE_PATTERN.search(glyph_name): msg = ["has no contours"] else: msg = [] else: for test in options.test_list: if test is not None: new_glyph, changed, msg = \ test(new_glyph, changed, msg, options) if not options.quiet_mode: if len(msg) == 0: if last_had_msg: print() print(".", end=' ') last_had_msg = False else: print(os.linesep + glyph_name, " ".join(msg), end=' ') last_had_msg = True if changed and options.allow_changes: font_changed = True original_contours = list(defcon_glyph) font_file.update_hash_entry(glyph_name, changed) if options.write_to_default_layer: fixed_glyph = defcon_glyph fixed_glyph.clearContours() else: # this will replace any pre-existing glyph: processed_layer.newGlyph(glyph_name) fixed_glyph = processed_layer[glyph_name] fixed_glyph.width = defcon_glyph.width fixed_glyph.height = defcon_glyph.height fixed_glyph.unicodes = defcon_glyph.unicodes point_pen = fixed_glyph.getPointPen() new_glyph.drawPoints(point_pen) if options.allow_decimal_coords: for contour in fixed_glyph: for point in contour: point.x = round(point.x, 3) point.y = round(point.y, 3) else: for contour in fixed_glyph: for point in contour: point.x = int(round(point.x)) point.y = int(round(point.y)) restore_contour_order(fixed_glyph, original_contours) # The following is needed when the script is called from another # script with Popen(): sys.stdout.flush() # update layer plist: the hash check call may have deleted processed layer # glyphs because the default layer glyph is newer. # At this point, we may have deleted glyphs in the # processed layer.writer.getGlyphSet() # will fail unless we update the contents.plist file to match. if options.allow_changes: ufoTools.validateLayers(font_path, False) if not font_changed: # Even if the program didn't change any glyphs, # we should still save updates to the src glyph hash file. print() font_file.close() else: print() font_file.save() if processed_glyph_count != seen_glyph_count: print("Skipped %s of %s glyphs." % (seen_glyph_count - processed_glyph_count, seen_glyph_count)) print("Done with font") return