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
Beispiel #4
0
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
Beispiel #5
0
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)
Beispiel #6
0
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
Beispiel #7
0
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)
Beispiel #8
0
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)
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #14
0
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
Beispiel #15
0
	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)
Beispiel #17
0
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)
Beispiel #18
0
	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)
Beispiel #19
0
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)
Beispiel #22
0
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
Beispiel #23
0
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
Beispiel #24
0
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
Beispiel #25
0
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)
Beispiel #27
0
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}')
Beispiel #28
0
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)
Beispiel #29
0
def test_runShellCmd_error(cmd, shell, str_out):
    assert runShellCmd(cmd, shell=shell) == str_out
Beispiel #30
0
def test_runShellCmd_timeout():
    assert runShellCmd('type1 -h', timeout=0) == ''
Beispiel #31
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()))
Beispiel #32
0
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)
Beispiel #33
0
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)
Beispiel #34
0
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()))
Beispiel #35
0
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()))
Beispiel #36
0
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
Beispiel #37
0
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
Beispiel #38
0
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
Beispiel #39
0
def test_runShellCmd_mac_linux(cmd, shell, str_out):
    assert runShellCmd(cmd, shell=shell) == str_out
Beispiel #40
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 = 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)
Beispiel #42
0
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