def merge_fonts(inputFontPath, outputPath, fontList, glyphList, fontDictList, fdGlyphDict): cidfontinfoPath = fdkutils.get_temp_file_path() makeCIDFontInfo(inputFontPath, cidfontinfoPath) lastFont = "" dstPath = '' for i, fontPath in enumerate(fontList): gaPath = fdkutils.get_temp_file_path() dstPath = fdkutils.get_temp_file_path() removeNotdef = i != 0 makeGAFile(gaPath, fontPath, glyphList, fontDictList, fdGlyphDict, removeNotdef) if lastFont: command = 'mergefonts -std -cid "%s" "%s" "%s" "%s" "%s" 2>&1' % ( cidfontinfoPath, dstPath, lastFont, gaPath, fontPath) else: command = 'mergefonts -std -cid "%s" "%s" "%s" "%s" 2>&1' % ( cidfontinfoPath, dstPath, gaPath, fontPath) log = fdkutils.runShellCmd(command) if "rror" in log: raise FontInfoParseError( "Error running command '%s'\nLog: %s" % (command, log)) lastFont = dstPath if os.path.exists(outputPath): os.remove(outputPath) os.rename(dstPath, outputPath)
def makeTempFonts(fontDictList, glyphSetList, fdGlyphDict, inputPath): fontList = [] for glyphList in glyphSetList: arg = ",".join(glyphList) tempPath = fdkutils.get_temp_file_path() command = "tx -t1 -g \"%s\" \"%s\" \"%s\" 2>&1" % ( arg, inputPath, tempPath) log = fdkutils.runShellCmd(command) if log: print("Have log output in subsetting command for %s to %s with " "%s glyphs." % (inputPath, tempPath, len(glyphList))) print(log) try: fdIndex = fdGlyphDict[glyphList[0]][0] except KeyError: # 'fontinfo' file was not provided; # assign list of glyphs to default FDDict fdIndex = 0 fdDict = fontDictList[fdIndex] fixFontDict(tempPath, fdDict) fontList.append(tempPath) return fontList
def getGlyphList(fPath, removeNotdef=False, original_font=False): command = "tx -dump -4 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontParseError("Error: Failed running 'tx -dump -4' on file " "%s" % fPath) # initial newline keeps us from picking up the first column header line nameList = re.findall(r"[\r\n]glyph.+?{([^,]+),", data) if not nameList: raise FontParseError("Error: Failed getting glyph names from file %s " "using tx." % fPath) if original_font: # make sure the original font has a .notdef glyph # and that it's the first glyph if '.notdef' not in nameList: raise FontParseError("Error: The font file %s does not have a " "'.notdef'." % fPath) elif nameList[0] != '.notdef': raise FontParseError("Error: '.notdef' is not the first glyph of " "font file %s" % fPath) if removeNotdef: nameList.remove(".notdef") return nameList
def makeTempFonts(fontDictList, glyphSetList, fdGlyphDict, inputPath): fontList = [] for glyphList in glyphSetList: arg = ",".join(glyphList) tempPath = fdkutils.get_temp_file_path() command = "tx -t1 -g \"%s\" \"%s\" \"%s\" 2>&1" % (arg, inputPath, tempPath) log = fdkutils.runShellCmd(command) if log: print("Have log output in subsetting command for %s to %s with " "%s glyphs." % (inputPath, tempPath, len(glyphList))) print(log) try: fdIndex = fdGlyphDict[glyphList[0]][0] except KeyError: # 'fontinfo' file was not provided; # assign list of glyphs to default FDDict fdIndex = 0 fdDict = fontDictList[fdIndex] fixFontDict(tempPath, fdDict) fontList.append(tempPath) return fontList
def merge_fonts(inputFontPath, outputPath, fontList, glyphList, fontDictList, fdGlyphDict): cidfontinfoPath = fdkutils.get_temp_file_path() makeCIDFontInfo(inputFontPath, cidfontinfoPath) lastFont = "" dstPath = '' for i, fontPath in enumerate(fontList): gaPath = fdkutils.get_temp_file_path() dstPath = fdkutils.get_temp_file_path() removeNotdef = i != 0 makeGAFile(gaPath, fontPath, glyphList, fontDictList, fdGlyphDict, removeNotdef) if lastFont: command = 'mergefonts -std -cid "%s" "%s" "%s" "%s" "%s" 2>&1' % ( cidfontinfoPath, dstPath, lastFont, gaPath, fontPath) else: command = 'mergefonts -std -cid "%s" "%s" "%s" "%s" 2>&1' % ( cidfontinfoPath, dstPath, gaPath, fontPath) log = fdkutils.runShellCmd(command) if "rror" in log: raise FontInfoParseError("Error running command '%s'\nLog: %s" % (command, log)) lastFont = dstPath if os.path.exists(outputPath): os.remove(outputPath) os.rename(dstPath, outputPath)
def getGlyphList(fPath, removeNotdef=False, original_font=False): command = "tx -dump -4 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontParseError("Error: Failed running 'tx -dump -4' on file " "%s" % fPath) # initial newline keeps us from picking up the first column header line nameList = re.findall(r"[\r\n]glyph.+?{([^,]+),", data) if not nameList: raise FontParseError("Error: Failed getting glyph names from file %s " "using tx." % fPath) if original_font: # make sure the original font has a .notdef glyph # and that it's the first glyph if '.notdef' not in nameList: raise FontParseError("Error: The font file %s does not have a " "'.notdef'." % fPath) elif nameList[0] != '.notdef': raise FontParseError("Error: '.notdef' is not the first glyph of " "font file %s" % fPath) if removeNotdef: nameList.remove(".notdef") return nameList
def compatibilizePaths(otfPath): tempPathCFF = otfPath + ".temp.cff" command = "tx -cff +b -std -no_opt \"%s\" \"%s\" 2>&1" % (otfPath, tempPathCFF) report = runShellCmd(command) if "fatal" in str(report): print(report) sys.exit(1) command = "sfntedit -a \"CFF \"=\"%s\" \"%s\" 2>&1" % (tempPathCFF, otfPath) report = runShellCmd(command) if "FATAL" in str(report): print(report) sys.exit(1) os.remove(tempPathCFF)
def compatibilizePaths(otfPath): tempPathCFF = otfPath + ".temp.cff" command = "tx -cff +b -std -no_opt \"%s\" \"%s\" 2>&1" % (otfPath, tempPathCFF) report = runShellCmd(command) if "fatal" in str(report): print(report) sys.exit(1) command = "sfntedit -a \"CFF \"=\"%s\" \"%s\" 2>&1" % (tempPathCFF, otfPath) report = runShellCmd(command) if "FATAL" in str(report): print(report) sys.exit(1) os.remove(tempPathCFF)
def CheckEnvironment(): txPath = 'tx' txError = 0 command = "%s -u 2>&1" % (txPath) report = fdkutils.runShellCmd(command) if "options" not in report: txError = 1 if txError: logMsg("Please re-install the FDK. The path to the program 'tx' is not in the environment variable PATH.") raise FDKEnvironmentError command = '"%s" -u 2>&1' % AUTOHINTEXE report = fdkutils.runShellCmd(command) if "version" not in report: logMsg("Please re-install the FDK. The path to the program 'autohintexe' is not in the environment variable PATH.") raise FDKEnvironmentError return
def CheckEnvironment(): txPath = 'tx' txError = 0 command = "%s -u 2>&1" % (txPath) report = fdkutils.runShellCmd(command) if "options" not in report: txError = 1 if txError: logMsg("Please re-install the FDK. The path to the program 'tx' is not in the environment variable PATH.") raise FDKEnvironmentError command = '"%s" -u 2>&1' % AUTOHINTEXE report = fdkutils.runShellCmd(command) if "version" not in report: logMsg("Please re-install the FDK. The path to the program 'autohintexe' is not in the environment variable PATH.") raise FDKEnvironmentError return
def openOpenTypeFile(path, outFilePath): # If input font is CFF or PS, build a dummy ttFont in memory.. # return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/ fontType = 0 # OTF tempPathCFF = fdkutils.get_temp_file_path() try: with open(path, "rb") as ff: head = ff.read(4) except (IOError, OSError): logMsg("Failed to open and read font file %s." % path) if head == b"OTTO": # it is an OTF font, can process file directly try: ttFont = TTFont(path) except (IOError, OSError): raise ACFontError("Error opening or reading from font file <%s>." % path) except TTLibError: raise ACFontError("Error parsing font file <%s>." % path) try: cffTable = ttFont["CFF "] except KeyError: raise ACFontError("Error: font is not a CFF font <%s>." % fontFileName) else: # It is not an OTF file. if head[0:2] == b'\x01\x00': # CFF file fontType = 1 tempPathCFF = path else: # It is a PS file. Convert to CFF. fontType = 2 print("Converting Type1 font to temp CFF font file...") command="tx -cff +b -std \"%s\" \"%s\" 2>&1" % (path, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg("Attempted to convert font %s from PS to a temporary CFF data file." % path) logMsg(report) raise ACFontError("Failed to convert PS font %s to a temp CFF font." % path) # now package the CFF font as an OTF font. with open(tempPathCFF, "rb") as ff: data = ff.read() try: ttFont = TTFont() cffModule = getTableModule('CFF ') cffTable = cffModule.table_C_F_F_('CFF ') ttFont['CFF '] = cffTable cffTable.decompile(data, ttFont) except: logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1])) logMsg("Attempted to read font %s as CFF." % path) raise ACFontError("Error parsing font file <%s>." % path) fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg) return fontData
def openOpenTypeFile(path, outFilePath): # If input font is CFF or PS, build a dummy ttFont in memory.. # return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/ fontType = 0 # OTF tempPathCFF = fdkutils.get_temp_file_path() try: with open(path, "rb") as ff: head = ff.read(4) except (IOError, OSError): logMsg("Failed to open and read font file %s." % path) if head == b"OTTO": # it is an OTF font, can process file directly try: ttFont = TTFont(path) except (IOError, OSError): raise ACFontError("Error opening or reading from font file <%s>." % path) except TTLibError: raise ACFontError("Error parsing font file <%s>." % path) try: cffTable = ttFont["CFF "] except KeyError: raise ACFontError("Error: font is not a CFF font <%s>." % fontFileName) else: # It is not an OTF file. if head[0:2] == b'\x01\x00': # CFF file fontType = 1 tempPathCFF = path else: # It is a PS file. Convert to CFF. fontType = 2 print("Converting Type1 font to temp CFF font file...") command="tx -cff +b -std \"%s\" \"%s\" 2>&1" % (path, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg("Attempted to convert font %s from PS to a temporary CFF data file." % path) logMsg(report) raise ACFontError("Failed to convert PS font %s to a temp CFF font." % path) # now package the CFF font as an OTF font. with open(tempPathCFF, "rb") as ff: data = ff.read() try: ttFont = TTFont() cffModule = getTableModule('CFF ') cffTable = cffModule.table_C_F_F_('CFF ') ttFont['CFF '] = cffTable cffTable.decompile(data, ttFont) except: logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1])) logMsg("Attempted to read font %s as CFF." % path) raise ACFontError("Error parsing font file <%s>." % path) fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg) return fontData
def getBlueFuzz(fPath): blueFuzz = 1.0 command = "tx -dump -0 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontInfoParseError("Error: Failed getting log from tx from %s, " "when trying to get FontName." % fPath) m = re.search(r"BlueFuzz\s+(\d+(?:\.\d+)*)", data) if m: blueFuzz = int(m.group(1)) return blueFuzz
def getBlueFuzz(fPath): blueFuzz = 1.0 command = "tx -dump -0 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontInfoParseError("Error: Failed getting log from tx from %s, " "when trying to get FontName." % fPath) m = re.search(r"BlueFuzz\s+(\d+(?:\.\d+)*)", data) if m: blueFuzz = int(m.group(1)) return blueFuzz
def saveChanges(self): ttFont = self.ttFont fontType = self.fontType inputPath = self.inputPath outFilePath = self.outFilePath overwriteOriginal = 0 if inputPath == outFilePath: overwriteOriginal = 1 tempPath = f'{inputPath}.temp.ac' if fontType == 0: # OTF if overwriteOriginal: ttFont.save(tempPath) ttFont.close() if os.path.exists(inputPath): try: os.remove(inputPath) os.rename(tempPath, inputPath) except (OSError, IOError): self.logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1])) self.logMsg("Error: could not overwrite original font file path '%s'. Hinted font file path is '%s'." % (inputPath, tempPath)) else: ttFont.save(outFilePath) ttFont.close() else: data = ttFont["CFF "].compile(ttFont) if fontType == 1: # CFF if overwriteOriginal: tf = open(inputPath, "wb") tf.write(data) tf.close() else: tf = open(outFilePath, "wb") tf.write(data) tf.close() elif fontType in (2, 3): # PS (PFA or PFB) tf = open(tempPath, "wb") tf.write(data) tf.close() finalPath = outFilePath command="tx -t1 -std \"%s\" \"%s\" 2>&1" % (tempPath, outFilePath) if fontType == 3: # PFB command = command.replace(" -t1 ", " -t1 -pfb ") report = fdkutils.runShellCmd(command) self.logMsg(report) if "fatal" in report: raise IOError("Failed to convert hinted font temp file with tx %s. Maybe target font font file '%s' is set to read-only. %s" % (tempPath, outFilePath, report)) if os.path.exists(tempPath): os.remove(tempPath)
def getFontName(fPath): command = "tx -dump -0 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontInfoParseError("Error: Failed getting log from tx from %s, " "when trying to get FontName." % fPath) m = re.search(r"FontName\s+\"([^\"]+)", data) if not m: print(data) raise FontInfoParseError("Error: Failed finding FontName in tx log " "from %s." % fPath) return m.group(1)
def getFontName(fPath): command = "tx -dump -0 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontInfoParseError("Error: Failed getting log from tx from %s, " "when trying to get FontName." % fPath) m = re.search(r"FontName\s+\"([^\"]+)", data) if not m: print(data) raise FontInfoParseError("Error: Failed finding FontName in tx log " "from %s." % fPath) return m.group(1)
def saveChanges(self): ttFont = self.ttFont fontType = self.fontType inputPath = self.inputPath outFilePath = self.outFilePath overwriteOriginal = 0 if inputPath == outFilePath: overwriteOriginal = 1 tempPath = "{}.temp.ac".format(inputPath) if fontType == 0: # OTF if overwriteOriginal: ttFont.save(tempPath) ttFont.close() if os.path.exists(inputPath): try: os.remove(inputPath) os.rename(tempPath, inputPath) except (OSError, IOError): self.logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1])) self.logMsg("Error: could not overwrite original font file path '%s'. Hinted font file path is '%s'." % (inputPath, tempPath)) else: ttFont.save(outFilePath) ttFont.close() else: data = ttFont["CFF "].compile(ttFont) if fontType == 1: # CFF if overwriteOriginal: tf = open(inputPath, "wb") tf.write(data) tf.close() else: tf = open(outFilePath, "wb") tf.write(data) tf.close() elif fontType == 2: # PS. tf = open(tempPath, "wb") tf.write(data) tf.close() finalPath = outFilePath command="tx -t1 -std \"%s\" \"%s\" 2>&1" % (tempPath, outFilePath) report = fdkutils.runShellCmd(command) self.logMsg(report) if "fatal" in report: raise IOError("Failed to convert hinted font temp file with tx %s. Maybe target font font file '%s' is set to read-only. %s" % (tempPath, outFilePath, report)) if os.path.exists(tempPath): os.remove(tempPath)
def mergeFontToCFF(srcPath, outputPath, doSubr): """ Used by makeotf. Assumes srcPath is a type 1 font,and outputPath is an OTF font. """ # First, convert src font to cff, and subroutinize it if so requested. tempPath = fdkutils.get_temp_file_path() subrArg = "" if doSubr: subrArg = " +S" command = "tx -cff +b%s \"%s\" \"%s\" 2>&1" % (subrArg, srcPath, tempPath) report = fdkutils.runShellCmd(command) if ("fatal" in report) or ("error" in report): print(report) raise FontInfoParseError("Failed to run 'tx -cff +b' on file %s" % srcPath) # Now merge it into the output file. command = "sfntedit -a CFF=\"%s\" \"%s\" 2>&1" % (tempPath, outputPath) report = fdkutils.runShellCmd(command) if ("fatal" in report) or ("error" in report): print(report) raise FontInfoParseError( "Failed to run 'sfntedit -a CFF=' on file %s" % srcPath)
def getFontBBox(fPath): command = "tx -mtx -2 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontInfoParseError("Error: Failed getting log from tx from %s, " "when trying to get FontBBox." % fPath) m = re.search(r"bbox[^{]+{([^}]+)}", data) if not m: print(data) raise FontInfoParseError("Error: Failed finding FontBBox in tx log " "from %s." % fPath) fontBBox = m.group(1).split(",") fontBBox = [int(val) for val in fontBBox] return fontBBox
def mergeFontToCFF(srcPath, outputPath, doSubr): """ Used by makeotf. Assumes srcPath is a type 1 font,and outputPath is an OTF font. """ # First, convert src font to cff, and subroutinize it if so requested. tempPath = fdkutils.get_temp_file_path() subrArg = "" if doSubr: subrArg = " +S" command = "tx -cff +b%s \"%s\" \"%s\" 2>&1" % (subrArg, srcPath, tempPath) report = fdkutils.runShellCmd(command) if ("fatal" in report) or ("error" in report): print(report) raise FontInfoParseError( "Failed to run 'tx -cff +b' on file %s" % srcPath) # Now merge it into the output file. command = "sfntedit -a CFF=\"%s\" \"%s\" 2>&1" % (tempPath, outputPath) report = fdkutils.runShellCmd(command) if ("fatal" in report) or ("error" in report): print(report) raise FontInfoParseError( "Failed to run 'sfntedit -a CFF=' on file %s" % srcPath)
def getFontBBox(fPath): command = "tx -mtx -2 \"%s\" 2>&1" % fPath data = fdkutils.runShellCmd(command) if not data: raise FontInfoParseError("Error: Failed getting log from tx from %s, " "when trying to get FontBBox." % fPath) m = re.search(r"bbox[^{]+{([^}]+)}", data) if not m: print(data) raise FontInfoParseError("Error: Failed finding FontBBox in tx log " "from %s." % fPath) fontBBox = m.group(1).split(",") fontBBox = [int(val) for val in fontBBox] return fontBBox
def CheckEnvironment(): tx_path = 'tx' txError = 0 command = "%s -u 2>&1" % tx_path report = fdkutils.runShellCmd(command) if "options" not in report: txError = 1 if txError: logMsg("Please check PATH and/or re-install the afdko. Cannot find: " "< %s >." % (tx_path)) logMsg("or the files referenced by the shell script is missing.") raise FDKEnvironmentError return tx_path
def CheckEnvironment(): tx_path = 'tx' txError = 0 command = "%s -u 2>&1" % tx_path report = fdkutils.runShellCmd(command) if "options" not in report: txError = 1 if txError: logMsg("Please check PATH and/or re-install the afdko. Cannot find: " "< %s >." % (tx_path)) logMsg("or the files referenced by the shell script is missing.") raise FDKEnvironmentError return tx_path
def makeCIDFontInfo(fontPath, cidfontinfoPath): cfiDict = {} for key in kCIDFontInfokeyList: cfiDict[key] = None cfiDict["Weight"] = "(Regular)" cfiDict["AdobeCopyright"] = "0" # get regular FontDict. command = "tx -0 \"%s\" 2>&1" % fontPath report = fdkutils.runShellCmd(command) if ("fatal" in report) or ("error" in report): print(report) raise FontInfoParseError("Failed to dump font dict using tx from " "font '%s'" % fontPath) for entry in TX_FIELDS: match = re.search(entry[0] + r"\s+(.+?)[\r\n]", report) if match: entry[2] = match.group(1) cfiDict["Registry"] = "Adobe" cfiDict["Ordering"] = "Identity" cfiDict["Supplement"] = "0" for entry in TX_FIELDS: if entry[2]: cfiDict[entry[1]] = entry[2] elif entry[1] in kRequiredCIDFontInfoFields: print("Error: did not find required info '%s' in tx dump of " "font '%s'." % (entry[1], fontPath)) try: with open(cidfontinfoPath, "w") as fp: for key in kCIDFontInfokeyList: value = cfiDict[key] if value is None: continue if value[0] == "\"": value = "(" + value[1:-1] + ")" string = "%s\t%s\n" % (key, value) fp.write(string) except (IOError, OSError): raise FontInfoParseError("Error. Could not open and write file '%s'" % cidfontinfoPath)
def makeCIDFontInfo(fontPath, cidfontinfoPath): cfiDict = {} for key in kCIDFontInfokeyList: cfiDict[key] = None cfiDict["Weight"] = "(Regular)" cfiDict["AdobeCopyright"] = "0" # get regular FontDict. command = "tx -0 \"%s\" 2>&1" % fontPath report = fdkutils.runShellCmd(command) if ("fatal" in report) or ("error" in report): print(report) raise FontInfoParseError("Failed to dump font dict using tx from " "font '%s'" % fontPath) for entry in TX_FIELDS: match = re.search(entry[0] + r"\s+(.+?)[\r\n]", report) if match: entry[2] = match.group(1) cfiDict["Registry"] = "Adobe" cfiDict["Ordering"] = "Identity" cfiDict["Supplement"] = "0" for entry in TX_FIELDS: if entry[2]: cfiDict[entry[1]] = entry[2] elif entry[1] in kRequiredCIDFontInfoFields: print("Error: did not find required info '%s' in tx dump of " "font '%s'." % (entry[1], fontPath)) try: with open(cidfontinfoPath, "w") as fp: for key in kCIDFontInfokeyList: value = cfiDict[key] if value is None: continue if value[0] == "\"": value = "(" + value[1:-1] + ")" string = tounicode("%s\t%s\n" % (key, value)) fp.write(string) except (IOError, OSError): raise FontInfoParseError( "Error. Could not open and write file '%s'" % cidfontinfoPath)
def test_runShellCmd_windows(cmd, shell): # The shell command call always produces output on Windows, # regardless of the value of the shell (True/False) and # no matter if the command/args are a list or a string assert runShellCmd(cmd, shell=shell) == (f'usage: type1 [text [font]]{linesep}')
def fixFontDict(tempPath, fdDict): txtPath = fdkutils.get_temp_file_path() command = "detype1 \"%s\" \"%s\" 2>&1" % (tempPath, txtPath) log = fdkutils.runShellCmd(command) if log: print(log) with open(txtPath, "r", encoding='utf-8') as fp: data = fp.read() # fix font name. We always search for it, as it is always present, # and we can use the following white space to get the file new line. m = re.search(r"(/FontName\s+/\S+\s+def)(\s+)", data) newLine = m.group(2) if not m: raise FontParseError("Failed to find FontName in input font! " "%s" % tempPath) if fdDict.FontName: target = "/FontName /%s def" % fdDict.FontName data = data[:m.start(1)] + target + data[m.end(1):] # fix em square if fdDict.OrigEmSqUnits: m = re.search(r"/FontMatrix\s+\[.+?\]\s+def", data) if not m: raise FontParseError("Failed to find FontMatrix in input font! " "%s" % tempPath) emUnits = getattr(fdDict, 'OrigEmSqUnits') a = 1.0 / emUnits target = "/FontMatrix [%s 0 0 %s 0 0] def" % (a, a) data = data[:m.start()] + target + data[m.end():] # fix StemSnapH. Remove StemSnapH if fdDict.StemSnapH # is not defined, else set it. m = re.search(r"/StemSnapH\s+\[.+?\]\s+def", data) if fdDict.DominantH: target = "/StemSnapH %s def" % fdDict.DominantH data = data[:m.start()] + target + data[m.end():] insertIndex = m.start() + len(target) else: if m: data = data[:m.start()] + data[m.end():] # fix StemSnapV. Remove StemSnapV entry if fdDict.StemSnapV # is not defined, else set it. m = re.search(r"/StemSnapV\s+\[.+?\]\s+def", data) if fdDict.DominantV: target = "/StemSnapV %s def" % fdDict.DominantV data = data[:m.start()] + target + data[m.end():] insertIndex = m.start() + len(target) else: if m: data = data[:m.start()] + data[m.end():] # LanguageGroup. Remove LanguageGroup entry if # fdDict.LanguageGroup is not defined, else set it. if fdDict.LanguageGroup: m = re.search(r"/LanguageGroup\s+\d+\s+def", data) if not m: target = "%s/LanguageGroup %s def" % (newLine, fdDict.LanguageGroup) data = data[:insertIndex] + data[insertIndex] + target + \ data[insertIndex:] else: target = "/LanguageGroup %s def" % fdDict.LanguageGroup data = data[:m.start()] + target + data[m.end():] else: m = re.search(r"/LanguageGroup\s+\d+\s+def", data) if m: data = data[:m.start()] + data[m.end():] # Fix BlueValues. Must be present. if fdDict.BlueValues: m = re.search(r"/BlueValues\s+\[.+?\]\s+def", data) if not m: raise FontParseError("Failed to find BlueValues in input font! " "%s" % tempPath) target = "/BlueValues %s def" % fdDict.BlueValues data = data[:m.start()] + target + data[m.end():] insertIndex = m.start() + len(target) # Fix OtherBlues, if present. Remove if there are no OtherBlues entry. m = re.search(r"/OtherBlues\s+\[.+?\]\s+def", data) if fdDict.OtherBlues: if not m: target = "%s/OtherBlues %s def" % (newLine, fdDict.OtherBlues) data = data[:insertIndex] + target + data[insertIndex:] else: target = "/OtherBlues %s def" % fdDict.OtherBlues data = data[:m.start()] + target + data[m.end():] else: if m: data = data[:m.start()] + data[m.end():] with open(txtPath, "w") as fp: fp.write(data) command = "type1 \"%s\" \"%s\" 2>&1" % (txtPath, tempPath) log = fdkutils.runShellCmd(command) if log: print(log)
def test_runShellCmd_error(cmd, shell, str_out): assert runShellCmd(cmd, shell=shell) == str_out
def test_runShellCmd_timeout(): assert runShellCmd('type1 -h', timeout=0) == ''
def hintFile(options): path = options.inputPath fontFileName = os.path.basename(path) logMsg("Hinting font %s. Start time: %s." % (path, time.asctime())) try: useHashMap = not options.logOnly # for UFO fonts only. We always use the hash map, unless the user has said to only report issues. fontData = openFile(path, options.outputPath, useHashMap) fontData.allowDecimalCoords = options.allowDecimalCoords if options.writeToDefaultLayer and hasattr(fontData, "setWriteToDefault"): # UFO fonts only fontData.setWriteToDefault() except (IOError, OSError): logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error opening or reading from font file <%s>." % fontFileName) except: logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error parsing font file <%s>." % fontFileName) # filter specified list, if any, with font list. fontGlyphList = fontData.getGlyphList() glyphList = filterGlyphList(options, fontGlyphList, fontFileName) if not glyphList: raise ACFontError("Error: selected glyph list is empty for font <%s>." % fontFileName) # temp file names for input and output bez files, and for the fontinfo file. tempBez = fdkutils.get_temp_file_path() tempBezNew = '{}{}'.format(tempBez, NEWBEZ_SUFFIX) tempFI = fdkutils.get_temp_file_path() psName = fontData.getPSName() if (not options.logOnly) and options.usePlistFile: fontPlist, fontPlistFilePath, isNewPlistFile = openFontPlistFile(psName, os.path.dirname(path)) if isNewPlistFile and not (options.hintAll or options.rehint): logMsg("No hint info plist file was found, so all glyphs are unknown to autohint. To hint all glyphs, run autohint again with option -a to hint all glyphs unconditionally.") logMsg("Done with font %s. End time: %s." % (path, time.asctime())) fontData.close() return # Check counter glyphs, if any. if options.hCounterGlyphs or options.vCounterGlyphs: missingList = filter(lambda name: name not in fontGlyphList, options.hCounterGlyphs + options.vCounterGlyphs) if missingList: logMsg( "\tError: glyph named in counter hint list file '%s' are not in font: %s" % (options.counterHintFile, missingList) ) # build alignment zone string if (options.printDefaultFDDict): logMsg("Showing default FDDict Values:") fdDict = fontData.getFontInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs) parseFontInfoString(str(fdDict)) fontData.close() return fdGlyphDict, fontDictList = fontData.getfdInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs, glyphList) if options.printFDDictList: # Print the user defined FontDicts, and exit. if fdGlyphDict: logMsg("Showing user-defined FontDict Values:") for fi in range(len(fontDictList)): fontDict = fontDictList[fi] logMsg("") logMsg(fontDict.DictName) parseFontInfoString(str(fontDict)) gnameList = [] itemList = fdGlyphDict.items() itemList.sort(cmpFDDictEntries) for gName, entry in itemList: if entry[0] == fi: gnameList.append(gName) logMsg("%d glyphs:" % len(gnameList)) if len(gnameList) > 0: gTxt = " ".join(gnameList) else: gTxt = "None" logMsg(gTxt) else: logMsg("There are no user-defined FontDict Values.") fontData.close() return if fdGlyphDict == None: fdDict = fontDictList[0] with open(tempFI, "w") as fp: fp.write(tounicode(fdDict.getFontInfo())) else: if not options.verbose: logMsg("Note: Using alternate FDDict global values from fontinfo file for some glyphs. Remove option '-q' to see which dict is used for which glyphs.") # for identifier in glyph-list: # Get charstring. removeHints = 1 isCID = fontData.isCID() lastFDIndex = None reportCB = ACreport anyGlyphChanged = 0 pListChanged = 0 if isCID: options.noFlex = 1 if options.verbose: verboseArg = "" else: verboseArg = " -q" dotCount = 0 curTime = time.time() if options.allowChanges: suppressEditArg = "" else: suppressEditArg = " -e" if options.noHintSub: supressHintSubArg = " -n" else: supressHintSubArg = "" if options.allowDecimalCoords: decimalArg = " -d" else: decimalArg = "" dotCount = 0 seenGlyphCount = 0 processedGlyphCount = 0 for name in glyphList: prevACIdentifier = None seenGlyphCount +=1 # Convert to bez format bezString, width, hasHints = fontData.convertToBez(name, removeHints, options.verbose, options.hintAll) processedGlyphCount += 1 if bezString == None: continue if "mt" not in bezString: # skip empty glyphs. continue # get new fontinfo string if FD array index has changed, as # as each FontDict has different alignment zones. gid = fontData.getGlyphID(name) if isCID: # fdIndex = fontData.getfdIndex(gid) if not fdIndex == lastFDIndex: lastFDIndex = fdIndex fdDict = fontData.getFontInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs, fdIndex) with open(tempFI, "w") as fp: fp.write(tounicode(fdDict.getFontInfo())) else: if (fdGlyphDict != None): try: fdIndex = fdGlyphDict[name][0] except KeyError: # use default dict. fdIndex = 0 if lastFDIndex != fdIndex: lastFDIndex = fdIndex fdDict = fontDictList[fdIndex] with open(tempFI, "w") as fp: fp.write(tounicode(fdDict.getFontInfo())) # Build autohint point list identifier oldBezString = "" oldHintBezString = "" if (not options.logOnly) and options.usePlistFile: # If the glyph is not in the plist file, then we skip it unless kReHintUnknown is set. # If the glyph is in the plist file and the outline has changed, we hint it. ACidentifier = makeACIdentifier(bezString) try: (prevACIdentifier, ACtime, oldBezString, oldHintBezString) = fontPlist[kACIDKey][name] except ValueError: (prevACIdentifier, ACtime) = fontPlist[kACIDKey][name] oldBezString = oldHintBezString = "" except KeyError: pListChanged = 1 # Didn't have an entry in tempList file, so we will add one. if hasHints and not options.rehint: # Glyphs is hinted, but not referenced in the plist file. Skip it unless options.rehint is seen if not isNewPlistFile: # Comment only if there is a plist file; otherwise, we'd be complaining for almost every glyph. logMsg("%s Skipping glyph - it has hints, but it is not in the hint info plist file." % aliasName(name)) dotCount = 0 continue if prevACIdentifier and (prevACIdentifier == ACidentifier): # there is an entry in the plist file and it matches what's in the font. if hasHints and not (options.hintAll or options.rehint): continue else: pListChanged = 1 if options.verbose: if fdGlyphDict: logMsg("Hinting %s with fdDict %s." % (aliasName(name), fdDict.DictName) ) else: logMsg("Hinting %s." % aliasName(name)) else: logMsg(".,") # Call auto-hint library on bez string. with open(tempBez, "wt") as bp: bp.write(tounicode(bezString)) #print "oldBezString", oldBezString #print "" #print "bezString", bezString if oldBezString != "" and oldBezString == bezString: newBezString = oldHintBezString else: if os.path.exists(tempBezNew): os.remove(tempBezNew) command = '"%s" %s%s%s%s -s %s -f "%s" "%s"' % (AUTOHINTEXE, verboseArg, suppressEditArg, supressHintSubArg, decimalArg, NEWBEZ_SUFFIX, tempFI, tempBez) if options.debug: print(command) report = fdkutils.runShellCmd(command) if report: if not options.verbose: logMsg("") # end series of "." logMsg(report) if os.path.exists(tempBezNew): bp = open(tempBezNew, "rt") newBezString = bp.read() bp.close() if options.debug: print("Wrote AC fontinfo data file to %s" % tempFI) print("Wrote AC output bez file to %s" % tempBezNew) else: os.remove(tempBezNew) else: newBezString = None if not newBezString: if not options.verbose: logMsg("") logMsg("%s Error - failure in processing outline data." % aliasName(name)) continue if not (("ry" in newBezString[:200]) or ("rb" in newBezString[:200]) or ("rm" in newBezString[:200]) or ("rv" in newBezString[:200])): print("No hints added!") if options.logOnly: continue # Convert bez to charstring, and update CFF. anyGlyphChanged = 1 fontData.updateFromBez(newBezString, name, width, options.verbose) if options.usePlistFile: bezString = "%% %s%s%s" % (name, os.linesep, newBezString) ACidentifier = makeACIdentifier(bezString) # add glyph hint entry to plist file if options.allowChanges: if prevACIdentifier and (prevACIdentifier != ACidentifier): logMsg("\t%s Glyph outline changed" % aliasName(name)) dotCount = 0 fontPlist[kACIDKey][name] = (ACidentifier, time.asctime(), bezString, newBezString ) if not options.verbose: print() # print final new line after progress dots. if options.debug: print("Wrote input AC bez file to %s" % tempBez) if not options.logOnly: if anyGlyphChanged: logMsg("Saving font file with new hints..." + time.asctime()) fontData.saveChanges() else: fontData.close() if options.usePlistFile: if options.rehint: logMsg("No new hints. All glyphs had hints that matched the hint record file %s." % (fontPlistFilePath)) if options.hintAll: logMsg("No new hints. All glyphs had hints that matched the hint history file %s, or were not in the history file and already had hints." % (fontPlistFilePath)) else: logMsg("No new hints. All glyphs were already hinted.") else: logMsg("No glyphs were hinted.") if options.usePlistFile and (anyGlyphChanged or pListChanged): # save font plist file. fontPlist.write(fontPlistFilePath) if processedGlyphCount != seenGlyphCount: logMsg("Skipped %s of %s glyphs." % (seenGlyphCount - processedGlyphCount, seenGlyphCount)) logMsg("Done with font %s. End time: %s." % (path, time.asctime()))
def main(args=None): if args is None: args = sys.argv[1:] if not args: args = ["-u"] mkot_options = '' if '-u' in args: print(__usage__) return if '-h' in args: print(__help__) return if '--mkot' in args: index = args.index('--mkot') args.pop(index) mkot_options = parse_makeotf_options(args.pop(index)) (dsPath, ) = args glyphSetsDiffer, master_paths = testGlyphSetsCompatible(dsPath) if glyphSetsDiffer: allowDecimalCoords = False logFile = tempfile.NamedTemporaryFile(delete=True).name tempDSPath, master_paths = buildTempDesignSpace(dsPath) print("Generating temp UFO master(s)...") ds_doc_reader = DesignSpaceDocumentReader( tempDSPath, ufoVersion=2, roundGeometry=(not allowDecimalCoords), verbose=False, logPath=logFile) ds_doc_reader.process(makeGlyphs=True, makeKerning=True, makeInfo=True) print("Building local otf's for master font paths...") curDir = os.getcwd() dsDir = os.path.dirname(dsPath) for master_path in master_paths: master_path = os.path.join(dsDir, master_path) masterDir = os.path.dirname(master_path) ufoName = os.path.basename(master_path) if ufoName.endswith(kTempUFOExt): otfName = ufoName[:-len(kTempUFOExt)] # copy the features.fea file from the original UFO master fea_file_path_from = os.path.join( master_path[:-len(kTempUFOExt)] + '.ufo', kFeaturesFile) fea_file_path_to = os.path.join(master_path, kFeaturesFile) if os.path.exists(fea_file_path_from): shutil.copyfile(fea_file_path_from, fea_file_path_to) else: otfName = os.path.splitext(ufoName)[0] otfName = otfName + ".otf" os.chdir(masterDir) cmd = "makeotf -nshw -f \"%s\" -o \"%s\" -r -nS %s 2>&1" % ( ufoName, otfName, mkot_options) log = runShellCmd(cmd) if ("FATAL" in log) or ("Failed to build" in log): print(log) if "Built" not in str(log): print("Error building OTF font for", master_path, log) print("makeotf cmd was '%s' in %s." % (cmd, masterDir)) else: print("Built OTF font for", master_path) compatibilizePaths(otfName) if ufoName.endswith(kTempUFOExt): shutil.rmtree(ufoName) os.chdir(curDir) if glyphSetsDiffer and os.path.exists(tempDSPath): os.remove(tempDSPath)
def main(args=None): if args is None: args = sys.argv[1:] if not args: args = ["-u"] mkot_options = '' if '-u' in args: print(__usage__) return if '-h' in args: print(__help__) return if '--mkot' in args: index = args.index('--mkot') args.pop(index) mkot_options = parse_makeotf_options(args.pop(index)) (dsPath,) = args glyphSetsDiffer, master_paths = testGlyphSetsCompatible(dsPath) if glyphSetsDiffer: allowDecimalCoords = False logFile = tempfile.NamedTemporaryFile(delete=True).name tempDSPath, master_paths = buildTempDesignSpace(dsPath) print("Generating temp UFO master(s)...") ds_doc_reader = DesignSpaceDocumentReader( tempDSPath, ufoVersion=2, roundGeometry=(not allowDecimalCoords), verbose=False, logPath=logFile) ds_doc_reader.process(makeGlyphs=True, makeKerning=True, makeInfo=True) print("Building local otf's for master font paths...") curDir = os.getcwd() dsDir = os.path.dirname(dsPath) for master_path in master_paths: master_path = os.path.join(dsDir, master_path) masterDir = os.path.dirname(master_path) ufoName = os.path.basename(master_path) if ufoName.endswith(kTempUFOExt): otfName = ufoName[:-len(kTempUFOExt)] # copy the features.fea file from the original UFO master fea_file_path_from = os.path.join( master_path[:-len(kTempUFOExt)] + '.ufo', kFeaturesFile) fea_file_path_to = os.path.join(master_path, kFeaturesFile) if os.path.exists(fea_file_path_from): shutil.copyfile(fea_file_path_from, fea_file_path_to) else: otfName = os.path.splitext(ufoName)[0] otfName = otfName + ".otf" os.chdir(masterDir) cmd = "makeotf -nshw -f \"%s\" -o \"%s\" -r -nS %s 2>&1" % ( ufoName, otfName, mkot_options) log = runShellCmd(cmd) if ("FATAL" in log) or ("Failed to build" in log): print(log) if "Built" not in str(log): print("Error building OTF font for", master_path, log) print("makeotf cmd was '%s' in %s." % (cmd, masterDir)) else: print("Built OTF font for", master_path) compatibilizePaths(otfName) if ufoName.endswith(kTempUFOExt): shutil.rmtree(ufoName) os.chdir(curDir) if glyphSetsDiffer and os.path.exists(tempDSPath): os.remove(tempDSPath)
def collectStemsFont(path, options): # use fontTools library to open font and extract CFF table. # If error, skip font and report error. fontFileName = os.path.basename(path) logMsg("") if options.doAlign: logMsg( "Collecting alignment zones for font %s. Start time: %s." % (path, time.asctime())) else: logMsg( "Collecting stems for font %s. Start time: %s." % (path, time.asctime())) try: fontData = openFile(path) except (IOError, OSError): logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error opening or reading from font file <%s>." % fontFileName) except: logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error parsing font file <%s>." % fontFileName) # filter specified list, if any, with font list. fontGlyphList = fontData.getGlyphList() glyphList = filterGlyphList(options, fontGlyphList, fontFileName) if not glyphList: raise ACFontError("Error: selected glyph list is empty for font <%s>." % fontFileName) tempBez = fdkutils.get_temp_file_path() tempReport = f'{tempBez}.rpt' tempFI = fdkutils.get_temp_file_path() # open font plist file, if any. If not, create empty font plist. psName = fontData.getPSName() # build alignment zone string allow_no_blues = 1 noFlex = 0 vCounterGlyphs = hCounterGlyphs = [] fdGlyphDict, fontDictList = fontData.getfdInfo(psName, path, allow_no_blues, noFlex, vCounterGlyphs, hCounterGlyphs, glyphList) if fdGlyphDict == None: fdDict = fontDictList[0] with open(tempFI, "w") as fp: fp.write(fdDict.getFontInfo()) else: if not options.verbose: logMsg("Note: Using alternate FDDict global values from fontinfo file for some glyphs. Remove option '-q' to see which dict is used for which glyphs.") removeHints = 1 isCID = fontData.isCID() lastFDIndex = None glyphReports = GlyphReports() if not options.verbose: dotCount = 0 curTime = time.time() for name in glyphList: if name == ".notdef": continue if options.verbose: logMsg("Checking %s." %name) else: newTime = time.time() if (newTime - curTime) > 1: print(".", end=' ') sys.stdout.flush() curTime = newTime dotCount +=1 if dotCount > 40: dotCount = 0 print("") # Convert to bez format bezString, width, hasHints = fontData.convertToBez(name, removeHints, options.verbose) if bezString == None: continue if "mt" not in bezString: # skip empty glyphs. continue # get new fontinfo string if FD array index has changed, as # as each FontDict has different alignment zones. gid = fontData.getGlyphID(name) if isCID: # fdIndex = fontData.getfdIndex(gid) if not fdIndex == lastFDIndex: lastFDIndex = fdIndex fdDict = fontData.getFontInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs, fdIndex) with open(tempFI, "w") as fp: fp.write(fdDict.getFontInfo()) else: if (fdGlyphDict != None): try: fdIndex = fdGlyphDict[name][0] except KeyError: # use default dict. fdIndex = 0 if lastFDIndex != fdIndex: lastFDIndex = fdIndex fdDict = fontDictList[fdIndex] with open(tempFI, "w") as fp: fp.write(fdDict.getFontInfo()) glyphReports.startGlyphName(name) # Call auto-hint library on bez string. with open(tempBez, "w") as bp: bp.write(bezString) if options.doAlign: doAlign = "-ra" else: doAlign = "-rs" if options.allStems: allStems = "-a" else: allStems = "" command = AUTOHINTEXE + " -q %s %s -f \"%s\" \"%s\" 2>&1" % (doAlign, allStems, tempFI, tempBez) if options.debug: print(command) log = fdkutils.runShellCmd(command) if log: print(log) if "number terminator while" in log: print(tempBez) sys.exit() if os.path.exists(tempReport): with open(tempReport, "r", encoding='utf-8') as bp: report = bp.read() if options.debug: print("Wrote AC fontinfo data file to", tempFI) print("Wrote AC output rpt file to", tempReport) report.strip() if report: glyphReports.addGlyphReport(report) if options.debug: rawData.append(report) else: print("Error - failure in processing outline data") report = None h_stem_list, v_stem_list, top_zone_list, bot_zone_list = glyphReports.getReportLists() if options.reportPath: reportPath = options.reportPath else: reportPath = path PrintReports(reportPath, h_stem_list, v_stem_list, top_zone_list, bot_zone_list) fontData.close() logMsg( "Done with font %s. End time: %s." % (path, time.asctime()))
def collectStemsFont(path, options): # use fontTools library to open font and extract CFF table. # If error, skip font and report error. fontFileName = os.path.basename(path) logMsg("") if options.doAlign: logMsg( "Collecting alignment zones for font %s. Start time: %s." % (path, time.asctime())) else: logMsg( "Collecting stems for font %s. Start time: %s." % (path, time.asctime())) try: fontData = openFile(path) except (IOError, OSError): logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error opening or reading from font file <%s>." % fontFileName) except: logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error parsing font file <%s>." % fontFileName) # filter specified list, if any, with font list. fontGlyphList = fontData.getGlyphList() glyphList = filterGlyphList(options, fontGlyphList, fontFileName) if not glyphList: raise ACFontError("Error: selected glyph list is empty for font <%s>." % fontFileName) tempBez = fdkutils.get_temp_file_path() tempReport = '{}{}'.format(tempBez, ".rpt") tempFI = fdkutils.get_temp_file_path() # open font plist file, if any. If not, create empty font plist. psName = fontData.getPSName() # build alignment zone string allow_no_blues = 1 noFlex = 0 vCounterGlyphs = hCounterGlyphs = [] fdGlyphDict, fontDictList = fontData.getfdInfo(psName, path, allow_no_blues, noFlex, vCounterGlyphs, hCounterGlyphs, glyphList) if fdGlyphDict == None: fdDict = fontDictList[0] with open(tempFI, "w") as fp: fp.write(tounicode(fdDict.getFontInfo())) else: if not options.verbose: logMsg("Note: Using alternate FDDict global values from fontinfo file for some glyphs. Remove option '-q' to see which dict is used for which glyphs.") removeHints = 1 isCID = fontData.isCID() lastFDIndex = None glyphReports = GlyphReports() if not options.verbose: dotCount = 0 curTime = time.time() for name in glyphList: if name == ".notdef": continue if options.verbose: logMsg("Checking %s." %name) else: newTime = time.time() if (newTime - curTime) > 1: print(".", end=' ') sys.stdout.flush() curTime = newTime dotCount +=1 if dotCount > 40: dotCount = 0 print("") # Convert to bez format bezString, width, hasHints = fontData.convertToBez(name, removeHints, options.verbose) if bezString == None: continue if "mt" not in bezString: # skip empty glyphs. continue # get new fontinfo string if FD array index has changed, as # as each FontDict has different alignment zones. gid = fontData.getGlyphID(name) if isCID: # fdIndex = fontData.getfdIndex(gid) if not fdIndex == lastFDIndex: lastFDIndex = fdIndex fdDict = fontData.getFontInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs, fdIndex) with open(tempFI, "w") as fp: fp.write(tounicode(fdDict.getFontInfo())) else: if (fdGlyphDict != None): try: fdIndex = fdGlyphDict[name][0] except KeyError: # use default dict. fdIndex = 0 if lastFDIndex != fdIndex: lastFDIndex = fdIndex fdDict = fontDictList[fdIndex] with open(tempFI, "w") as fp: fp.write(tounicode(fdDict.getFontInfo())) glyphReports.startGlyphName(name) # Call auto-hint library on bez string. with open(tempBez, "w") as bp: bp.write(tounicode(bezString)) if options.doAlign: doAlign = "-ra" else: doAlign = "-rs" if options.allStems: allStems = "-a" else: allStems = "" command = AUTOHINTEXE + " -q %s %s -f \"%s\" \"%s\" 2>&1" % (doAlign, allStems, tempFI, tempBez) if options.debug: print(command) log = fdkutils.runShellCmd(command) if log: print(log) if "number terminator while" in log: print(tempBez) sys.exit() if os.path.exists(tempReport): with open(tempReport, "r", encoding='utf-8') as bp: report = bp.read() if options.debug: print("Wrote AC fontinfo data file to", tempFI) print("Wrote AC output rpt file to", tempReport) report.strip() if report: glyphReports.addGlyphReport(report) if options.debug: rawData.append(report) else: print("Error - failure in processing outline data") report = None h_stem_list, v_stem_list, top_zone_list, bot_zone_list = glyphReports.getReportLists() if options.reportPath: reportPath = options.reportPath else: reportPath = path PrintReports(reportPath, h_stem_list, v_stem_list, top_zone_list, bot_zone_list) fontData.close() logMsg( "Done with font %s. End time: %s." % (path, time.asctime()))
def openFile(path, txPath): # If input font is CFF or PS, build a dummy ttFont. tempPathCFF = None cffPath = None # If it is CID-keyed font, we need to convert it to a name-keyed font. This is a hack, but I really don't want to add CID support to # the very simple-minded PDF library. command = "%s -dump -0 \"%s\" 2>&1" % (txPath, path) report = fdkutils.runShellCmd(command) if "CIDFontName" in report: tfd, tempPath1 = tempfile.mkstemp() os.close(tfd) command = "%s -t1 -decid -usefd 0 \"%s\" \"%s\" 2>&1" % ( txPath, path, tempPath1) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg(report) logMsg( "Failed to convert CID-keyed font %s to a temporary Typ1 data file." % path) tfd, tempPathCFF = tempfile.mkstemp() os.close(tfd) command = "%s -cff +b \"%s\" \"%s\" 2>&1" % (txPath, tempPath1, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg(report) logMsg( "Failed to convert CID-keyed font %s to a temporary CFF data file." % path) cffPath = tempPathCFF os.remove(tempPath1) elif os.path.isdir(path): # See if it is a UFO font by truing to dump it. command = "%s -dump -0 \"%s\" 2>&1" % (txPath, path) report = fdkutils.runShellCmd(command) if not "sup.srcFontType" in report: logMsg(report) logMsg("Failed to open directory %s as a UFO font." % path) tfd, tempPathCFF = tempfile.mkstemp() os.close(tfd) command = "%s -cff +b \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg(report) logMsg( "Failed to convert ufo font %s to a temporary CFF data file." % path) cffPath = tempPathCFF else: try: with open(path, "rb") as ff: head = ff.read(10) except (IOError, OSError): traceback.print_exc() raise FontError( "Failed to open and read font file %s. Check file/directory permissions." % path) if len(head) < 10: raise FontError( "Error: font file was zero size: may be a resource fork font, which this program does not process. <%s>." % path) # it is an OTF/TTF font, can process file directly elif head[:4] in (b"OTTO", b"true", b"\0\1\0\0"): try: ttFont = TTFont(path) except (IOError, OSError): raise FontError( "Error opening or reading from font file <%s>." % path) except TTLibError: raise if 'CFF ' not in ttFont and 'glyf' not in ttFont: raise FontError( "Error: font is not a CFF or TrueType font <%s>." % path) return ttFont, tempPathCFF # It is not an SFNT file. elif head[0:2] == b'\x01\x00': # CFF file cffPath = path elif b"%" not in head: # not a PS file either logMsg("Font file must be a PS, CFF or OTF fontfile: %s." % path) raise FontError("Font file must be PS, CFF or OTF file: %s." % path) else: # It is a PS file. Convert to CFF. tfd, tempPathCFF = tempfile.mkstemp() os.close(tfd) cffPath = tempPathCFF command = "%s -cff +b \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg( "Attempted to convert font %s from PS to a temporary CFF data file." % path) logMsg(report) raise FontError( "Failed to convert PS font %s to a temp CFF font." % path) # now package the CFF font as an OTF font with open(cffPath, "rb") as ff: data = ff.read() try: ttFont = TTFont() cffModule = getTableModule('CFF ') cffTable = cffModule.table_C_F_F_('CFF ') ttFont['CFF '] = cffTable cffTable.decompile(data, ttFont) except: traceback.print_exc() logMsg("Attempted to read font %s as CFF." % path) raise FontError("Error parsing font file <%s>." % path) return ttFont, tempPathCFF
def getOptions(): global gLogFile options = ACOptions() i = 1 numOptions = len(sys.argv) while i < numOptions: arg = sys.argv[i] if options.inputPath: raise ACOptionParseError("Option Error: All options must preceed the input font path <%s>." % arg) if arg == "-h": print(__help__) command = '"%s" -v' % AUTOHINTEXE report = fdkutils.runShellCmd(command) logMsg( report) raise ACOptionParseError elif arg == "-u": print(__usage__) command = '"%s" -v' % AUTOHINTEXE report = fdkutils.runShellCmd(command) logMsg( report) raise ACOptionParseError elif arg == "-hfd": print(__FDDoc__) raise ACOptionParseError elif arg == "-pfd": options.printDefaultFDDict = 1 elif arg == "-pfdl": options.printFDDictList = 1 elif arg == "-hf": options.usePlistFile = 1 elif arg == "-a": options.hintAll = 1 elif arg == "-all": options.hintAll = 1 elif arg == "-r": options.rehint = 1 elif arg == "-q": options.verbose = 0 elif arg == "-c": options.allowChanges = 1 elif arg == "-nf": options.noFlex = 1 elif arg == "-ns": options.noHintSub = 1 elif arg == "-nb": options.allow_no_blues = 1 elif arg in ["-xg", "-g"]: if arg == "-xg": options.excludeGlyphList = 1 i = i +1 glyphString = sys.argv[i] if glyphString[0] == "-": raise ACOptionParseError("Option Error: it looks like the first item in the glyph list following '-g' is another option.") options.glyphList += parseGlyphListArg(glyphString) elif arg in ["-xgf", "-gf"]: if arg == "-xgf": options.excludeGlyphList = 1 i = i +1 filePath = sys.argv[i] if filePath[0] == "-": raise ACOptionParseError("Option Error: it looks like the the glyph list file following '-gf' is another option.") try: gf = open(filePath, "rt") glyphString = gf.read() gf.close() except (IOError,OSError): raise ACOptionParseError("Option Error: could not open glyph list file <%s>." % filePath) options.glyphList += parseGlyphListArg(glyphString) elif arg == "-cf": i = i +1 filePath = sys.argv[i] if filePath[0] == "-": raise ACOptionParseError("Option Error: it looks like the the counter hint glyph list file following '-cf' is another option.") try: options.counterHintFile = filePath options.hCounterGlyphs, options.vCounterGlyphs = parseCounterHintData(filePath) except (IOError,OSError): raise ACOptionParseError("Option Error: could not open counter hint glyph list file <%s>." % filePath) elif arg == "-logOnly": options.logOnly = 1 elif arg == "-log": i = i +1 options.logFilePath = sys.argv[i] gLogFile = open(options.logFilePath, "wt") elif arg == "-o": i = i +1 options.outputPath = sys.argv[i] elif arg == "-d": options.debug = 1 elif arg in ["-decimal", "-dec"]: options.allowDecimalCoords = True elif arg =="-wd": options.writeToDefaultLayer = 1 elif arg[0] == "-": raise ACOptionParseError("Option Error: Unknown option <%s>." % arg) else: options.inputPath = arg i += 1 if not options.inputPath: raise ACOptionParseError("Option Error: You must provide a font file path.") if not os.path.exists(options.inputPath): raise ACOptionParseError("Option Error: The input font file path %s' does not exist." % (options.inputPath)) else: options.inputPath = options.inputPath.rstrip(os.sep) # might be a UFO font. auto completion in some shells adds a dir separator, which then causes problems with os.path.dirname(). checkFontinfoFile(options) if options.logOnly: options.verbose = 1 options.hintAll = 1 return options
def openFile(path, txPath): # If input font is CFF or PS, build a dummy ttFont. tempPathCFF = None cffPath = None # If it is CID-keyed font, we need to convert it to a name-keyed font. This is a hack, but I really don't want to add CID support to # the very simple-minded PDF library. command="%s -dump -0 \"%s\" 2>&1" % (txPath, path) report = fdkutils.runShellCmd(command) if "CIDFontName" in report: tfd,tempPath1 = tempfile.mkstemp() os.close(tfd) command="%s -t1 -decid -usefd 0 \"%s\" \"%s\" 2>&1" % (txPath, path, tempPath1) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg(report) logMsg("Failed to convert CID-keyed font %s to a temporary Typ1 data file." % path) tfd,tempPathCFF = tempfile.mkstemp() os.close(tfd) command="%s -cff +b \"%s\" \"%s\" 2>&1" % (txPath, tempPath1, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg(report) logMsg("Failed to convert CID-keyed font %s to a temporary CFF data file." % path) cffPath = tempPathCFF os.remove(tempPath1) elif os.path.isdir(path): # See if it is a UFO font by truing to dump it. command="%s -dump -0 \"%s\" 2>&1" % (txPath, path) report = fdkutils.runShellCmd(command) if not "sup.srcFontType" in report: logMsg(report) logMsg("Failed to open directory %s as a UFO font." % path) tfd,tempPathCFF = tempfile.mkstemp() os.close(tfd) command="%s -cff +b \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg(report) logMsg("Failed to convert ufo font %s to a temporary CFF data file." % path) cffPath = tempPathCFF else: try: with open(path, "rb") as ff: head = ff.read(10) except (IOError, OSError): traceback.print_exc() raise FontError("Failed to open and read font file %s. Check file/directory permissions." % path) if len(head) < 10: raise FontError("Error: font file was zero size: may be a resource fork font, which this program does not process. <%s>." % path) # it is an OTF/TTF font, can process file directly elif head[:4] in (b"OTTO", b"true", b"\0\1\0\0"): try: ttFont = TTFont(path) except (IOError, OSError): raise FontError("Error opening or reading from font file <%s>." % path) except TTLibError: raise if 'CFF ' not in ttFont and 'glyf' not in ttFont: raise FontError("Error: font is not a CFF or TrueType font <%s>." % path) return ttFont, tempPathCFF # It is not an SFNT file. elif head[0:2] == b'\x01\x00': # CFF file cffPath = path elif b"%" not in head: # not a PS file either logMsg("Font file must be a PS, CFF or OTF fontfile: %s." % path) raise FontError("Font file must be PS, CFF or OTF file: %s." % path) else: # It is a PS file. Convert to CFF. tfd,tempPathCFF = tempfile.mkstemp() os.close(tfd) cffPath = tempPathCFF command="%s -cff +b \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF) report = fdkutils.runShellCmd(command) if "fatal" in report: logMsg("Attempted to convert font %s from PS to a temporary CFF data file." % path) logMsg(report) raise FontError("Failed to convert PS font %s to a temp CFF font." % path) # now package the CFF font as an OTF font with open(cffPath, "rb") as ff: data = ff.read() try: ttFont = TTFont() cffModule = getTableModule('CFF ') cffTable = cffModule.table_C_F_F_('CFF ') ttFont['CFF '] = cffTable cffTable.decompile(data, ttFont) except: traceback.print_exc() logMsg("Attempted to read font %s as CFF." % path) raise FontError("Error parsing font file <%s>." % path) return ttFont, tempPathCFF
def test_runShellCmd_mac_linux(cmd, shell, str_out): assert runShellCmd(cmd, shell=shell) == str_out
def hintFile(options): path = options.inputPath fontFileName = os.path.basename(path) logMsg("Hinting font %s. Start time: %s." % (path, time.asctime())) try: useHashMap = not options.logOnly # for UFO fonts only. We always use the hash map, unless the user has said to only report issues. fontData = openFile(path, options.outputPath, useHashMap) fontData.allowDecimalCoords = options.allowDecimalCoords if options.writeToDefaultLayer and hasattr(fontData, "setWriteToDefault"): # UFO fonts only fontData.setWriteToDefault() except (IOError, OSError): logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error opening or reading from font file <%s>." % fontFileName) except: logMsg( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]) raise ACFontError("Error parsing font file <%s>." % fontFileName) # filter specified list, if any, with font list. fontGlyphList = fontData.getGlyphList() glyphList = filterGlyphList(options, fontGlyphList, fontFileName) if not glyphList: raise ACFontError("Error: selected glyph list is empty for font <%s>." % fontFileName) # temp file names for input and output bez files, and for the fontinfo file. tempBez = fdkutils.get_temp_file_path() tempBezNew = f'{tempBez}{NEWBEZ_SUFFIX}' tempFI = fdkutils.get_temp_file_path() psName = fontData.getPSName() if (not options.logOnly) and options.usePlistFile: fontPlist, fontPlistFilePath, isNewPlistFile = openFontPlistFile(psName, os.path.dirname(path)) if isNewPlistFile and not (options.hintAll or options.rehint): logMsg("No hint info plist file was found, so all glyphs are unknown to autohint. To hint all glyphs, run autohint again with option -a to hint all glyphs unconditionally.") logMsg("Done with font %s. End time: %s." % (path, time.asctime())) fontData.close() return # Check counter glyphs, if any. if options.hCounterGlyphs or options.vCounterGlyphs: missingList = filter(lambda name: name not in fontGlyphList, options.hCounterGlyphs + options.vCounterGlyphs) if missingList: logMsg( "\tError: glyph named in counter hint list file '%s' are not in font: %s" % (options.counterHintFile, missingList) ) # build alignment zone string if (options.printDefaultFDDict): logMsg("Showing default FDDict Values:") fdDict = fontData.getFontInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs) parseFontInfoString(str(fdDict)) fontData.close() return fdGlyphDict, fontDictList = fontData.getfdInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs, glyphList) if options.printFDDictList: # Print the user defined FontDicts, and exit. if fdGlyphDict: logMsg("Showing user-defined FontDict Values:") for fi in range(len(fontDictList)): fontDict = fontDictList[fi] logMsg("") logMsg(fontDict.DictName) parseFontInfoString(str(fontDict)) gnameList = [] itemList = fdGlyphDict.items() itemList.sort(cmpFDDictEntries) for gName, entry in itemList: if entry[0] == fi: gnameList.append(gName) logMsg("%d glyphs:" % len(gnameList)) if len(gnameList) > 0: gTxt = " ".join(gnameList) else: gTxt = "None" logMsg(gTxt) else: logMsg("There are no user-defined FontDict Values.") fontData.close() return if fdGlyphDict == None: fdDict = fontDictList[0] with open(tempFI, "w") as fp: fp.write(fdDict.getFontInfo()) else: if not options.verbose: logMsg("Note: Using alternate FDDict global values from fontinfo file for some glyphs. Remove option '-q' to see which dict is used for which glyphs.") # for identifier in glyph-list: # Get charstring. removeHints = 1 isCID = fontData.isCID() lastFDIndex = None reportCB = ACreport anyGlyphChanged = 0 pListChanged = 0 if isCID: options.noFlex = 1 if options.verbose: verboseArg = "" else: verboseArg = " -q" dotCount = 0 curTime = time.time() if options.allowChanges: suppressEditArg = "" else: suppressEditArg = " -e" if options.noHintSub: supressHintSubArg = " -n" else: supressHintSubArg = "" if options.allowDecimalCoords: decimalArg = " -d" else: decimalArg = "" dotCount = 0 seenGlyphCount = 0 processedGlyphCount = 0 for name in glyphList: prevACIdentifier = None seenGlyphCount +=1 # Convert to bez format bezString, width, hasHints = fontData.convertToBez(name, removeHints, options.verbose, options.hintAll) processedGlyphCount += 1 if bezString == None: continue if "mt" not in bezString: # skip empty glyphs. continue # get new fontinfo string if FD array index has changed, as # as each FontDict has different alignment zones. gid = fontData.getGlyphID(name) if isCID: # fdIndex = fontData.getfdIndex(gid) if not fdIndex == lastFDIndex: lastFDIndex = fdIndex fdDict = fontData.getFontInfo(psName, path, options.allow_no_blues, options.noFlex, options.vCounterGlyphs, options.hCounterGlyphs, fdIndex) with open(tempFI, "w") as fp: fp.write(fdDict.getFontInfo()) else: if (fdGlyphDict != None): try: fdIndex = fdGlyphDict[name][0] except KeyError: # use default dict. fdIndex = 0 if lastFDIndex != fdIndex: lastFDIndex = fdIndex fdDict = fontDictList[fdIndex] with open(tempFI, "w") as fp: fp.write(fdDict.getFontInfo()) # Build autohint point list identifier oldBezString = "" oldHintBezString = "" if (not options.logOnly) and options.usePlistFile: # If the glyph is not in the plist file, then we skip it unless kReHintUnknown is set. # If the glyph is in the plist file and the outline has changed, we hint it. ACidentifier = makeACIdentifier(bezString) try: (prevACIdentifier, ACtime, oldBezString, oldHintBezString) = fontPlist[kACIDKey][name] except ValueError: (prevACIdentifier, ACtime) = fontPlist[kACIDKey][name] oldBezString = oldHintBezString = "" except KeyError: pListChanged = 1 # Didn't have an entry in tempList file, so we will add one. if hasHints and not options.rehint: # Glyphs is hinted, but not referenced in the plist file. Skip it unless options.rehint is seen if not isNewPlistFile: # Comment only if there is a plist file; otherwise, we'd be complaining for almost every glyph. logMsg("%s Skipping glyph - it has hints, but it is not in the hint info plist file." % aliasName(name)) dotCount = 0 continue if prevACIdentifier and (prevACIdentifier == ACidentifier): # there is an entry in the plist file and it matches what's in the font. if hasHints and not (options.hintAll or options.rehint): continue else: pListChanged = 1 if options.verbose: if fdGlyphDict: logMsg("Hinting %s with fdDict %s." % (aliasName(name), fdDict.DictName) ) else: logMsg("Hinting %s." % aliasName(name)) else: logMsg(".,") # Call auto-hint library on bez string. with open(tempBez, "wt") as bp: bp.write(bezString) #print "oldBezString", oldBezString #print "" #print "bezString", bezString if oldBezString != "" and oldBezString == bezString: newBezString = oldHintBezString else: if os.path.exists(tempBezNew): os.remove(tempBezNew) command = '"%s" %s%s%s%s -s %s -f "%s" "%s"' % (AUTOHINTEXE, verboseArg, suppressEditArg, supressHintSubArg, decimalArg, NEWBEZ_SUFFIX, tempFI, tempBez) if options.debug: print(command) report = fdkutils.runShellCmd(command) if report: if not options.verbose: logMsg("") # end series of "." logMsg(report) if os.path.exists(tempBezNew): bp = open(tempBezNew, "rt") newBezString = bp.read() bp.close() if options.debug: print("Wrote AC fontinfo data file to %s" % tempFI) print("Wrote AC output bez file to %s" % tempBezNew) else: os.remove(tempBezNew) else: newBezString = None if not newBezString: if not options.verbose: logMsg("") logMsg("%s Error - failure in processing outline data." % aliasName(name)) continue if not (("ry" in newBezString[:200]) or ("rb" in newBezString[:200]) or ("rm" in newBezString[:200]) or ("rv" in newBezString[:200])): print("No hints added!") if options.logOnly: continue # Convert bez to charstring, and update CFF. anyGlyphChanged = 1 fontData.updateFromBez(newBezString, name, width, options.verbose) if options.usePlistFile: bezString = "%% %s%s%s" % (name, os.linesep, newBezString) ACidentifier = makeACIdentifier(bezString) # add glyph hint entry to plist file if options.allowChanges: if prevACIdentifier and (prevACIdentifier != ACidentifier): logMsg("\t%s Glyph outline changed" % aliasName(name)) dotCount = 0 fontPlist[kACIDKey][name] = (ACidentifier, time.asctime(), bezString, newBezString ) if not options.verbose: print() # print final new line after progress dots. if options.debug: print("Wrote input AC bez file to %s" % tempBez) if not options.logOnly: if anyGlyphChanged: logMsg("Saving font file with new hints..." + time.asctime()) fontData.saveChanges() else: fontData.close() if options.usePlistFile: if options.rehint: logMsg("No new hints. All glyphs had hints that matched the hint record file %s." % (fontPlistFilePath)) if options.hintAll: logMsg("No new hints. All glyphs had hints that matched the hint history file %s, or were not in the history file and already had hints." % (fontPlistFilePath)) else: logMsg("No new hints. All glyphs were already hinted.") else: logMsg("No glyphs were hinted.") if options.usePlistFile and (anyGlyphChanged or pListChanged): # save font plist file. with open(fontPlistFilePath, 'wb') as f: plistlib.dump(fontPlist, f) if processedGlyphCount != seenGlyphCount: logMsg("Skipped %s of %s glyphs." % (seenGlyphCount - processedGlyphCount, seenGlyphCount)) logMsg("Done with font %s. End time: %s." % (path, time.asctime()))
def fixFontDict(tempPath, fdDict): txtPath = fdkutils.get_temp_file_path() command = "detype1 \"%s\" \"%s\" 2>&1" % (tempPath, txtPath) log = fdkutils.runShellCmd(command) if log: print(log) with open(txtPath, "r", encoding='utf-8') as fp: data = fp.read() # fix font name. We always search for it, as it is always present, # and we can use the following white space to get the file new line. m = re.search(r"(/FontName\s+/\S+\s+def)(\s+)", data) newLine = m.group(2) if not m: raise FontParseError("Failed to find FontName in input font! " "%s" % tempPath) if fdDict.FontName: target = "/FontName /%s def" % fdDict.FontName data = data[:m.start(1)] + target + data[m.end(1):] # fix em square if fdDict.OrigEmSqUnits: m = re.search(r"/FontMatrix\s+\[.+?\]\s+def", data) if not m: raise FontParseError("Failed to find FontMatrix in input font! " "%s" % tempPath) emUnits = getattr(fdDict, 'OrigEmSqUnits') a = 1.0 / emUnits target = "/FontMatrix [%s 0 0 %s 0 0] def" % (a, a) data = data[:m.start()] + target + data[m.end():] # fix StemSnapH. Remove StemSnapH if fdDict.StemSnapH # is not defined, else set it. m = re.search(r"/StemSnapH\s+\[.+?\]\s+def", data) if fdDict.DominantH: target = "/StemSnapH %s def" % fdDict.DominantH data = data[:m.start()] + target + data[m.end():] insertIndex = m.start() + len(target) else: if m: data = data[:m.start()] + data[m.end():] # fix StemSnapV. Remove StemSnapV entry if fdDict.StemSnapV # is not defined, else set it. m = re.search(r"/StemSnapV\s+\[.+?\]\s+def", data) if fdDict.DominantV: target = "/StemSnapV %s def" % fdDict.DominantV data = data[:m.start()] + target + data[m.end():] insertIndex = m.start() + len(target) else: if m: data = data[:m.start()] + data[m.end():] # LanguageGroup. Remove LanguageGroup entry if # fdDict.LanguageGroup is not defined, else set it. if fdDict.LanguageGroup: m = re.search(r"/LanguageGroup\s+\d+\s+def", data) if not m: target = "%s/LanguageGroup %s def" % (newLine, fdDict.LanguageGroup) data = data[:insertIndex] + data[insertIndex] + target + \ data[insertIndex:] else: target = "/LanguageGroup %s def" % fdDict.LanguageGroup data = data[:m.start()] + target + data[m.end():] else: m = re.search(r"/LanguageGroup\s+\d+\s+def", data) if m: data = data[:m.start()] + data[m.end():] # Fix BlueValues. Must be present. if fdDict.BlueValues: m = re.search(r"/BlueValues\s+\[.+?\]\s+def", data) if not m: raise FontParseError("Failed to find BlueValues in input font! " "%s" % tempPath) target = "/BlueValues %s def" % fdDict.BlueValues data = data[:m.start()] + target + data[m.end():] insertIndex = m.start() + len(target) # Fix OtherBlues, if present. Remove if there are no OtherBlues entry. m = re.search(r"/OtherBlues\s+\[.+?\]\s+def", data) if fdDict.OtherBlues: if not m: target = "%s/OtherBlues %s def" % (newLine, fdDict.OtherBlues) data = data[:insertIndex] + target + data[insertIndex:] else: target = "/OtherBlues %s def" % fdDict.OtherBlues data = data[:m.start()] + target + data[m.end():] else: if m: data = data[:m.start()] + data[m.end():] with open(txtPath, "w") as fp: fp.write(data) command = "type1 \"%s\" \"%s\" 2>&1" % (txtPath, tempPath) log = fdkutils.runShellCmd(command) if log: print(log)
def getOptions(): global gLogFile options = ACOptions() i = 1 numOptions = len(sys.argv) while i < numOptions: arg = sys.argv[i] if options.inputPath: raise ACOptionParseError("Option Error: All options must preceed the input font path <%s>." % arg) if arg == "-h": print(__help__) command = '"%s" -v' % AUTOHINTEXE report = fdkutils.runShellCmd(command) logMsg( report) raise ACOptionParseError elif arg == "-u": print(__usage__) command = '"%s" -v' % AUTOHINTEXE report = fdkutils.runShellCmd(command) logMsg( report) raise ACOptionParseError elif arg == "-hfd": print(__FDDoc__) raise ACOptionParseError elif arg == "-pfd": options.printDefaultFDDict = 1 elif arg == "-pfdl": options.printFDDictList = 1 elif arg == "-hf": options.usePlistFile = 1 elif arg == "-a": options.hintAll = 1 elif arg == "-all": options.hintAll = 1 elif arg == "-r": options.rehint = 1 elif arg == "-q": options.verbose = 0 elif arg == "-c": options.allowChanges = 1 elif arg == "-nf": options.noFlex = 1 elif arg == "-ns": options.noHintSub = 1 elif arg == "-nb": options.allow_no_blues = 1 elif arg in ["-xg", "-g"]: if arg == "-xg": options.excludeGlyphList = 1 i = i +1 glyphString = sys.argv[i] if glyphString[0] == "-": raise ACOptionParseError("Option Error: it looks like the first item in the glyph list following '-g' is another option.") options.glyphList += parseGlyphListArg(glyphString) elif arg in ["-xgf", "-gf"]: if arg == "-xgf": options.excludeGlyphList = 1 i = i +1 filePath = sys.argv[i] if filePath[0] == "-": raise ACOptionParseError("Option Error: it looks like the the glyph list file following '-gf' is another option.") try: gf = open(filePath, "rt") glyphString = gf.read() gf.close() except (IOError,OSError): raise ACOptionParseError("Option Error: could not open glyph list file <%s>." % filePath) options.glyphList += parseGlyphListArg(glyphString) elif arg == "-cf": i = i +1 filePath = sys.argv[i] if filePath[0] == "-": raise ACOptionParseError("Option Error: it looks like the the counter hint glyph list file following '-cf' is another option.") try: options.counterHintFile = filePath options.hCounterGlyphs, options.vCounterGlyphs = parseCounterHintData(filePath) except (IOError,OSError): raise ACOptionParseError("Option Error: could not open counter hint glyph list file <%s>." % filePath) elif arg == "-logOnly": options.logOnly = 1 elif arg == "-log": i = i +1 options.logFilePath = sys.argv[i] gLogFile = open(options.logFilePath, "wt") elif arg == "-o": i = i +1 options.outputPath = sys.argv[i] elif arg == "-d": options.debug = 1 elif arg in ["-decimal", "-dec"]: options.allowDecimalCoords = True elif arg =="-wd": options.writeToDefaultLayer = 1 elif arg[0] == "-": raise ACOptionParseError("Option Error: Unknown option <%s>." % arg) else: options.inputPath = arg i += 1 if not options.inputPath: raise ACOptionParseError("Option Error: You must provide a font file path.") if not os.path.exists(options.inputPath): raise ACOptionParseError("Option Error: The input font file path %s' does not exist." % (options.inputPath)) else: options.inputPath = options.inputPath.rstrip(os.sep) # might be a UFO font. auto completion in some shells adds a dir separator, which then causes problems with os.path.dirname(). checkFontinfoFile(options) if options.logOnly: options.verbose = 1 options.hintAll = 1 return options