示例#1
0
    def __init__(self, path, font_format):
        self.inputPath = path
        self.font_format = font_format

        if font_format == "OTF":
            # It is an OTF font, we can process it directly.
            font = TTFont(path)
            if "CFF " not in font:
                raise FontParseError("OTF font has no CFF table <%s>." % path)
        else:
            # Else, package it in an OTF font.
            if font_format == "CFF":
                with open(path, "rb") as fp:
                    data = fp.read()
            else:
                fd, temp_path = tempfile.mkstemp()
                os.close(fd)
                try:
                    _run_tx(["-cff", "+b", "-std", path, temp_path])
                    with open(temp_path, "rb") as fp:
                        data = fp.read()
                finally:
                    os.remove(temp_path)

            font = TTFont()
            font['CFF '] = newTable('CFF ')
            font['CFF '].decompile(data, font)

        self.ttFont = font
        self.cffTable = font["CFF "]

        # for identifier in glyph-list:
        # Get charstring.
        self.topDict = self.cffTable.cff.topDictIndex[0]
        self.charStrings = self.topDict.CharStrings
示例#2
0
def _compileReferencedFeatureFile(inPath,
                                  outPath,
                                  relativePath,
                                  font,
                                  verbose=False,
                                  recursionDepth=0):
    """
    Compile the file given in inPath and write it to outPath.
    """
    if not os.path.exists(inPath):
        # XXX silently fail here?
        return
    # compile and write this file
    with open(inPath, "r") as f:
        text = f.read()
    text, referencedFiles = _compileFeatureText(text,
                                                font,
                                                relativePath,
                                                verbose=verbose,
                                                recursionDepth=recursionDepth)
    with open(outPath, "w") as f:
        f.write(text)
    # recurse through the referenced files
    for referenceInPath, referenceOutPath in referencedFiles:
        _compileReferencedFeatureFile(referenceInPath,
                                      referenceOutPath,
                                      relativePath,
                                      font,
                                      verbose=verbose,
                                      recursionDepth=recursionDepth + 1)
示例#3
0
def assert_equals_test_file(path, test_filename):
    with open(path) as fp:
        actual = fp.read()

    test_path = os.path.join(os.path.dirname(__file__), test_filename)
    with open(test_path) as fp:
        expected = fp.read()

    assert actual == expected
示例#4
0
def test_unicodes(tmpdir):
    tmpdir = str(tmpdir)
    testDocPath = os.path.join(tmpdir, "testUnicodes.designspace")
    testDocPath2 = os.path.join(tmpdir, "testUnicodes_roundtrip.designspace")
    masterPath1 = os.path.join(tmpdir, "masters", "masterTest1.ufo")
    masterPath2 = os.path.join(tmpdir, "masters", "masterTest2.ufo")
    instancePath1 = os.path.join(tmpdir, "instances", "instanceTest1.ufo")
    instancePath2 = os.path.join(tmpdir, "instances", "instanceTest2.ufo")
    doc = DesignSpaceDocument()
    # add master 1
    s1 = SourceDescriptor()
    s1.filename = os.path.relpath(masterPath1, os.path.dirname(testDocPath))
    s1.name = "master.ufo1"
    s1.copyInfo = True
    s1.location = dict(weight=0)
    doc.addSource(s1)
    # add master 2
    s2 = SourceDescriptor()
    s2.filename = os.path.relpath(masterPath2, os.path.dirname(testDocPath))
    s2.name = "master.ufo2"
    s2.location = dict(weight=1000)
    doc.addSource(s2)
    # add instance 1
    i1 = InstanceDescriptor()
    i1.filename = os.path.relpath(instancePath1, os.path.dirname(testDocPath))
    i1.name = "instance.ufo1"
    i1.location = dict(weight=500)
    glyphData = dict(name="arrow", mute=True, unicodes=[100, 200, 300])
    i1.glyphs['arrow'] = glyphData
    doc.addInstance(i1)
    # now we have sources and instances, but no axes yet.
    doc.axes = []  # clear the axes
    # write some axes
    a1 = AxisDescriptor()
    a1.minimum = 0
    a1.maximum = 1000
    a1.default = 0
    a1.name = "weight"
    a1.tag = "wght"
    doc.addAxis(a1)
    # write the document
    doc.write(testDocPath)
    assert os.path.exists(testDocPath)
    # import it again
    new = DesignSpaceDocument()
    new.read(testDocPath)
    new.write(testDocPath2)
    # compare the file contents
    f1 = open(testDocPath, 'r', encoding='utf-8')
    t1 = f1.read()
    f1.close()
    f2 = open(testDocPath2, 'r', encoding='utf-8')
    t2 = f2.read()
    f2.close()
    assert t1 == t2
    # check the unicode values read from the document
    assert new.instances[0].glyphs['arrow']['unicodes'] == [100, 200, 300]
def assert_equals_test_file(path, test_filename):
    with open(path) as fp:
        actual = fp.read()

    test_path = os.path.join(os.path.dirname(__file__), test_filename)
    with open(test_path) as fp:
        expected = fp.read()

    assert actual == expected
示例#6
0
def __removeConditionMinimumMaximumDesignSpace(path):
    # only for testing, so we can make an invalid designspace file
    # without making the designSpaceDocument also support it.
    f = open(path, 'r', encoding='utf-8')
    d = f.read()
    f.close()
    d = d.replace(' minimum="100"', '')
    f = open(path, 'w', encoding='utf-8')
    f.write(d)
    f.close()
示例#7
0
def _addUnwrappedCondition(path):
    # only for testing, so we can make an invalid designspace file
    # older designspace files may have conditions that are not wrapped in a conditionset
    # These can be read into a new conditionset.
    with open(path, 'r', encoding='utf-8') as f:
        d = f.read()
    print(d)
    d = d.replace('<rule name="named.rule.1">', '<rule name="named.rule.1">\n\t<condition maximum="22" minimum="33" name="axisName_a" />')
    with open(path, 'w', encoding='utf-8') as f:
        f.write(d)
def _addUnwrappedCondition(path):
    # only for testing, so we can make an invalid designspace file
    # older designspace files may have conditions that are not wrapped in a conditionset
    # These can be read into a new conditionset.
    with open(path, 'r', encoding='utf-8') as f:
        d = f.read()
    print(d)
    d = d.replace('<rule name="named.rule.1">', '<rule name="named.rule.1">\n\t<condition maximum="22" minimum="33" name="axisName_a" />')
    with open(path, 'w', encoding='utf-8') as f:
        f.write(d)
示例#9
0
def test_unicodes(tmpdir):
    tmpdir = str(tmpdir)
    testDocPath = os.path.join(tmpdir, "testUnicodes.designspace")
    testDocPath2 = os.path.join(tmpdir, "testUnicodes_roundtrip.designspace")
    masterPath1 = os.path.join(tmpdir, "masters", "masterTest1.ufo")
    masterPath2 = os.path.join(tmpdir, "masters", "masterTest2.ufo")
    instancePath1 = os.path.join(tmpdir, "instances", "instanceTest1.ufo")
    instancePath2 = os.path.join(tmpdir, "instances", "instanceTest2.ufo")
    doc = DesignSpaceDocument()
    # add master 1
    s1 = SourceDescriptor()
    s1.filename = os.path.relpath(masterPath1, os.path.dirname(testDocPath))
    s1.name = "master.ufo1"
    s1.copyInfo = True
    s1.location = dict(weight=0)
    doc.addSource(s1)
    # add master 2
    s2 = SourceDescriptor()
    s2.filename = os.path.relpath(masterPath2, os.path.dirname(testDocPath))
    s2.name = "master.ufo2"
    s2.location = dict(weight=1000)
    doc.addSource(s2)
    # add instance 1
    i1 = InstanceDescriptor()
    i1.filename = os.path.relpath(instancePath1, os.path.dirname(testDocPath))
    i1.name = "instance.ufo1"
    i1.location = dict(weight=500)
    glyphData = dict(name="arrow", mute=True, unicodes=[100, 200, 300])
    i1.glyphs['arrow'] = glyphData
    doc.addInstance(i1)
    # now we have sources and instances, but no axes yet.
    doc.axes = []   # clear the axes
    # write some axes
    a1 = AxisDescriptor()
    a1.minimum = 0
    a1.maximum = 1000
    a1.default = 0
    a1.name = "weight"
    a1.tag = "wght"
    doc.addAxis(a1)
    # write the document
    doc.write(testDocPath)
    assert os.path.exists(testDocPath)
    # import it again
    new = DesignSpaceDocument()
    new.read(testDocPath)
    new.write(testDocPath2)
    # compare the file contents
    with open(testDocPath, 'r', encoding='utf-8') as f1:
        t1 = f1.read()
    with open(testDocPath2, 'r', encoding='utf-8') as f2:
        t2 = f2.read()
    assert t1 == t2
    # check the unicode values read from the document
    assert new.instances[0].glyphs['arrow']['unicodes'] == [100,200,300]
示例#10
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
示例#11
0
def readDesignSpaceFile(options):
    """ Read design space file.
    build a new instancesList with all the instances from the ds file

    - Promote all the source and instance filename attributes from relative
      to absolute paths
    - Write a temporary ds file
    - Return a path to the temporary ds file, and the current instances list.
    """

    instanceEntryList = []
    logger.info("Reading design space file '%s' ..." % options.dsPath)

    with open(options.dsPath, "r", encoding='utf-8') as f:
        data = f.read()

    ds = ET.XML(data)

    instances = ds.find("instances")

    # Remove any instances that are not in the specified list of instance
    # indices, from the option -i.
    if options.indexList:
        newInstanceXMLList = instances.findall("instance")
        numInstances = len(newInstanceXMLList)
        instanceIndex = numInstances
        while instanceIndex > 0:
            instanceIndex -= 1
            instanceXML = newInstanceXMLList[instanceIndex]
            if instanceIndex not in options.indexList:
                instances.remove(instanceXML)

    # We want to build all remaining instances.
    for instanceXML in instances:
        familyName = instanceXML.attrib["familyname"]
        styleName = instanceXML.attrib["stylename"]
        curPath = instanceXML.attrib["filename"]
        logger.info("Adding %s %s to build list." % (familyName, styleName))
        instanceEntryList.append(curPath)
        if os.path.exists(curPath):
            glyphDir = os.path.join(curPath, "glyphs")
            if os.path.exists(glyphDir):
                shutil.rmtree(glyphDir, ignore_errors=True)
    if not instanceEntryList:
        logger.error("Failed to find any instances in the ds file '%s' that "
                     "have the postscriptfilename attribute" % options.dsPath)
        return None, None

    dsPath = "{}.temp".format(options.dsPath)
    data = ET.tostring(ds)
    with open(dsPath, "wb") as f:
        f.write(tobytes(data, encoding='utf-8'))

    return dsPath, instanceEntryList
示例#12
0
def __removeAxesFromDesignSpace(path):
    # only for testing, so we can make an invalid designspace file
    # without making the designSpaceDocument also support it.
    f = open(path, 'r', encoding='utf-8')
    d = f.read()
    f.close()
    start = d.find("<axes>")
    end = d.find("</axes>") + len("</axes>")
    n = d[0:start] + d[end:]
    f = open(path, 'w', encoding='utf-8')
    f.write(n)
    f.close()
示例#13
0
 def _expect_designspace(self, doc, expected_path):
     actual_path = self.write_to_tmp_path(doc, "generated.designspace")
     with open(actual_path, mode="r", encoding="utf-8") as f:
         actual = f.readlines()
     with open(expected_path, mode="r", encoding="utf-8") as f:
         expected = f.readlines()
     if actual != expected:
         expected_name = os.path.basename(expected_path)
         for line in difflib.unified_diff(
             expected, actual, fromfile=expected_name, tofile="<generated>"
         ):
             sys.stderr.write(line)
         self.fail("*.designspace file is different from expected")
示例#14
0
def _check_save_path(path_str):
    test_path = os.path.abspath(os.path.realpath(path_str))
    del_test_file = True
    try:
        if os.path.exists(test_path):
            del_test_file = False
        open(test_path, 'a').close()
        if del_test_file:
            os.remove(test_path)
    except (IOError, OSError):
        raise argparse.ArgumentTypeError(
            "{} is not a valid path to write to.".format(test_path))
    return test_path
示例#15
0
 def build(self, featureFile):
     path = self.temp_path(suffix=".fea")
     with open(path, "w", encoding="utf-8") as outfile:
         outfile.write(featureFile)
     font = makeTTFont()
     addOpenTypeFeatures(path, font)
     return font
示例#16
0
def getOptions():
	options = ACOptions()
	i = 1
	numOptions = len(sys.argv)
	while i < numOptions:
		arg = sys.argv[i]
		if options.fileList and arg[0] == "-":
			raise ACOptionParseError("Option Error: All file names must follow all other options <%s>." % arg)

		if arg == "-h":
			logMsg(__help__)
			sys.exit(0)
		elif arg == "-u":
			logMsg(__usage__)
			sys.exit(0)
		elif arg == "-all":
			options.allStems = 1
		elif arg == "-a":
			options.doAlign = 1
		elif arg == "-d":
			options.debug = 1
		elif arg == "-q":
			options.verbose = 0
		elif arg == "-o":
			i = i +1
			options.reportPath = sys.argv[i]
		elif arg == "-new":
			options.new = 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:
				with open(filePath, "r", encoding='utf-8') as gf:
					glyphString = gf.read()
			except (IOError,OSError):
				raise ACOptionParseError("Option Error: could not open glyph list file <%s>." %  filePath)
			options.glyphList += parseGlyphListArg(glyphString)
		elif arg[0] == "-":
			raise ACOptionParseError("Option Error: Unknown option <%s>." %  arg)
		else:
			arg = arg.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().
			options.fileList += [arg]
		i  += 1

	if not options.fileList:
		raise ACOptionParseError("Option Error: You must provide at least one font file path.")

	return options
示例#17
0
def convertFontToCID(inputPath, outputPath, fontinfoPath=None):
    """
    Takes in a path to the font file to convert, a path to save the result,
    and an optional path to a '(cid)fontinfo' file.
    """
    if fontinfoPath and os.path.exists(fontinfoPath):
        with open(fontinfoPath, "r", encoding='utf-8') as fi:
            fontInfoData = fi.read()
    else:
        fontInfoData = ''

    glyphList = getGlyphList(inputPath, False, True)
    fontBBox = getFontBBox(inputPath)
    fontName = getFontName(inputPath)
    blueFuzz = getBlueFuzz(inputPath)
    maxY = fontBBox[3]
    minY = fontBBox[1]

    # Start with an uninitialized entry for the default FDDict 0
    fontDictList = [FDDict()]

    fdGlyphDict, fontDictList, _ = parseFontInfoFile(
        fontDictList, fontInfoData, glyphList, maxY, minY, fontName, blueFuzz)

    glyphSetList = makeSortedGlyphLists(glyphList, fdGlyphDict)

    fontList = makeTempFonts(fontDictList, glyphSetList, fdGlyphDict,
                             inputPath)

    merge_fonts(inputPath, outputPath, fontList, glyphList, fontDictList,
                fdGlyphDict)
示例#18
0
def convertFontToCID(inputPath, outputPath, fontinfoPath=None):
    """
    Takes in a path to the font file to convert, a path to save the result,
    and an optional path to a '(cid)fontinfo' file.
    """
    if fontinfoPath and os.path.exists(fontinfoPath):
        with open(fontinfoPath, "r", encoding='utf-8') as fi:
            fontInfoData = fi.read()
    else:
        fontInfoData = ''

    glyphList = getGlyphList(inputPath, False, True)
    fontBBox = getFontBBox(inputPath)
    fontName = getFontName(inputPath)
    blueFuzz = getBlueFuzz(inputPath)
    maxY = fontBBox[3]
    minY = fontBBox[1]

    # Start with an uninitialized entry for the default FDDict 0
    fontDictList = [FDDict()]

    fdGlyphDict, fontDictList, _ = parseFontInfoFile(
        fontDictList, fontInfoData, glyphList, maxY, minY, fontName, blueFuzz)

    glyphSetList = makeSortedGlyphLists(glyphList, fdGlyphDict)

    fontList = makeTempFonts(fontDictList, glyphSetList, fdGlyphDict,
                             inputPath)

    merge_fonts(inputPath, outputPath, fontList, glyphList, fontDictList,
                fdGlyphDict)
示例#19
0
 def _read_txt_file(self, path):
     """
     Reads a text file and returns a list of its lines.
     """
     # Hard code a first line; this way the difflib results start
     # from 1 instead of zero, thus matching the file's line numbers
     lines = ['']
     try:
         with open(path, "r", encoding=self.encoding) as f:
             for i, line in enumerate(f.readlines(), 1):
                 # Skip lines that change, such as timestamps
                 if self._line_to_skip(line):
                     logger.debug("Matched begin of line. Skipped: {}"
                                  "".format(line.rstrip()))
                     # Blank the line instead of actually skipping (via
                     # 'continue'); this way the difflib results show the
                     # correct line numbers
                     line = ''
                 # Skip specific lines, referenced by number
                 elif i in self.skip_lines:
                     logger.debug("Matched line #{}. Skipped: {}"
                                  "".format(i, line.rstrip()))
                     line = ''
                 # Skip lines that match regex
                 elif self.skip_regex and self.skip_regex.match(line):
                     logger.debug("Matched regex begin of line. Skipped: {}"
                                  "".format(line.rstrip()))
                     line = ''
                 # Use os-native line separator to enable running difflib
                 lines.append(line.rstrip() + os.linesep)
     except UnicodeDecodeError:
         logger.error("Couldn't read text file using '{}' encoding.\n"
                      "      File path: {}".format(self.encoding, path))
         sys.exit(1)
     return lines
示例#20
0
def parseLayoutFile(filePath):
    layoutDict = None

    try:
        fp = open(filePath, "rt")
        data = fp.read()
        fp.close()
    except (IOError, OSError):
        raise OptionParseError(
            "Option Error: could not open and read the layout file <%s>." %
            filePath)

    entryList = re.findall(r"(\d+)\s+(\S+)\s+(\S+)\s+(\S+)", data)
    if len(entryList) < 2:
        print(
            "Error: Failed to parse layout file %s. Did not match expected entry format."
            % filePath)
        raise OptionParseError
    print("Found %s entries in layout file %s. Mac CID: %s" %
          (len(entryList), os.path.basename(filePath), entryList[-1][0]))
    layoutDict = {}
    index = 0
    for entry in entryList:
        gname = "cid" + entry[0].zfill(5)
        layoutDict[gname] = [entry[1], entry[2],
                             entry[3]]  # add cide key-> family, face dir, name
        reversekey = repr(entry[1:])
        layoutDict[reversekey] = [
            gname, entry[1], entry[2], entry[3]
        ]  # add name key -> family, face, cid as cidXXXX
        entryList = None
    if "cid00000" in layoutDict:
        layoutDict[".notdef"] = layoutDict["cid00000"]
    return layoutDict
示例#21
0
 def _read_txt_file(self, path):
     """
     Reads a text file and returns a list of its lines.
     """
     # Hard code a first line; this way the difflib results start
     # from 1 instead of zero, thus matching the file's line numbers
     lines = ['']
     try:
         with open(path, "r", encoding=self.encoding) as f:
             for i, line in enumerate(f.readlines(), 1):
                 # Skip lines that change, such as timestamps
                 if self._line_to_skip(line):
                     logger.debug("Matched begin of line. Skipped: {}"
                                  "".format(line.rstrip()))
                     # Blank the line instead of actually skipping (via
                     # 'continue'); this way the difflib results show the
                     # correct line numbers
                     line = ''
                 # Skip specific lines, referenced by number
                 elif i in self.skip_lines:
                     logger.debug("Matched line #{}. Skipped: {}"
                                  "".format(i, line.rstrip()))
                     # Blank the line instead of actually skipping (via
                     # 'continue'); this way the difflib results show the
                     # correct line numbers
                     line = ''
                 # Use os-native line separator to enable running difflib
                 lines.append(line.rstrip() + os.linesep)
     except UnicodeDecodeError:
         logger.error("Couldn't read text file using '{}' encoding.\n"
                      "      File path: {}".format(self.encoding, path))
         sys.exit(1)
     return lines
示例#22
0
def PrintReports(path, h_stem_list, v_stem_list, top_zone_list, bot_zone_list):
    items = ([h_stem_list,
              srtCnt], [v_stem_list,
                        srtCnt], [top_zone_list,
                                  srtRevVal], [bot_zone_list, srtVal])
    atime = time.asctime()
    suffixes = (".hstm.txt", ".vstm.txt", ".top.txt", ".bot.txt")
    titles = (
        "Horizontal Stem List for %s on %s\n" % (path, atime),
        "Vertical Stem List for %s on %s\n" % (path, atime),
        "Top Zone List for %s on %s\n" % (path, atime),
        "Bottom Zone List for %s on %s\n" % (path, atime),
    )
    headers = (
        "Count\tWidth\tGlyph List\n",
        "Count\tWidth\tGlyph List\n",
        "Count\tTop Zone\tGlyph List\n",
        "Count\tBottom Zone\tGlyph List\n",
    )
    for i, item in enumerate(items):
        rep_list, sortFunc = item
        if not rep_list:
            continue
        fName = '{}{}'.format(path, suffixes[i])
        title = titles[i]
        header = headers[i]
        try:
            with open(fName, "w") as fp:
                fp.write(tounicode(title))
                fp.write(tounicode(header))
                for item in formatReport(rep_list, sortFunc):
                    fp.write(tounicode(item))
                print("Wrote %s" % fName)
        except (IOError, OSError):
            print("Error creating file %s!" % fName)
示例#23
0
def parseLayoutFile(filePath):
	layoutDict = None

	try:
		fp = open(filePath, "rt")
		data = fp.read()
		fp.close()
	except (IOError,OSError):
		raise OptionParseError("Option Error: could not open and read the layout file <%s>." %  filePath)

	entryList = re.findall(r"(\d+)\s+(\S+)\s+(\S+)\s+(\S+)", data)
	if len(entryList) < 2:
		print("Error: Failed to parse layout file %s. Did not match expected entry format." % filePath)
		raise OptionParseError
	print("Found %s entries in layout file %s. Mac CID: %s" % (len(entryList), os.path.basename(filePath), entryList[-1][0]))
	layoutDict = {}
	index = 0
	for entry in entryList:
		gname = "cid" + entry[0].zfill(5)
		layoutDict[gname] = [entry[1], entry[2], entry[3]] # add cide key-> family, face dir, name
		reversekey = repr(entry[1:])
		layoutDict[reversekey] = [gname, entry[1], entry[2], entry[3]] # add name key -> family, face, cid as cidXXXX
		entryList = None
	if "cid00000" in layoutDict:
		layoutDict[".notdef"] = layoutDict["cid00000"]
	return layoutDict
示例#24
0
def main():
    try:
        options = getOptions()
    except ACOptionParseError as e:
        logMsg(e)
        return 1

    # verify that all files exist.
    haveFiles = True
    for path in options.fileList:
        if not os.path.exists(path):
            logMsg("File does not exist: <%s>." % path)
            haveFiles = False
    if not haveFiles:
        return 1

    for path in options.fileList:
        if options.new:
            if options.reportPath:
                reportPath = options.reportPath
            else:
                reportPath = path
            foundOne = checkReportExists(reportPath, options.doAlign)
            if foundOne:
                logMsg("Skipping %s, as a report already exists." % (path))
                continue
        try:
            collectStemsFont(path, options)
        except (ACFontError, ufotools.UFOParseError) as e:
            logMsg("\t%s" % e)
            return 1
        if options.debug:
            with open("rawdata.txt", "w") as fp:
                fp.write(tounicode('\n'.join(rawData)))
示例#25
0
def makeGAFile(gaPath, fontPath, glyphList, fontDictList, fdGlyphDict,
               removeNotdef):
    """
    Creates a glyph alias file for each FDDict.
    These files will be used by 'mergefonts' tool.
    For documentation on the format of this file, run 'mergefonts -h'.
    """
    glyph_list = getGlyphList(fontPath, removeNotdef)

    try:
        fdIndex = fdGlyphDict[glyph_list[0]][0]  # [fdIndex value, gi]
    except KeyError:
        fdIndex = 0

    fdDict = fontDictList[fdIndex]
    lineList = [""]

    lang_group = fdDict.LanguageGroup
    if lang_group is None:
        langGroup = " 0"
    else:
        langGroup = " %s" % lang_group

    dictName = "%s_%s" % (fdDict.FontName, fdDict.DictName)

    for glyph_name in glyph_list:
        gid = glyphList.index(glyph_name)
        lineList.append("%s\t%s" % (gid, glyph_name))

    lineList.append("")
    gaText = "mergefonts %s%s%s" % (dictName, langGroup, '\n'.join(lineList))

    with open(gaPath, "wb") as gf:
        gf.write(tobytes(gaText))
示例#26
0
def main():
	try:
		options = getOptions()
	except ACOptionParseError as e:
		logMsg(e)
		return 1

	# verify that all files exist.
	haveFiles = True
	for path in options.fileList:
		if not os.path.exists(path):
			logMsg( "File does not exist: <%s>." % path)
			haveFiles = False
	if not haveFiles:
		return 1

	for path in options.fileList:
		if options.new:
			if options.reportPath:
				reportPath = options.reportPath
			else:
				reportPath = path
			foundOne = checkReportExists(reportPath, options.doAlign)
			if foundOne:
				logMsg( "Skipping %s, as a report already exists." % (path))
				continue
		try:
			collectStemsFont(path, options)
		except (ACFontError, ufotools.UFOParseError) as e:
			logMsg( "\t%s" % e)
			return 1
		if options.debug:
			with open("rawdata.txt", "w") as fp:
				fp.write(tounicode('\n'.join(rawData)))
示例#27
0
    def getfdInfo(self, allow_no_blues, noFlex, vCounterGlyphs, hCounterGlyphs,
                  glyphList, fdIndex=0):
        fdGlyphDict = None
        fdDict = self.getFontInfo(allow_no_blues, noFlex,
                                  vCounterGlyphs, hCounterGlyphs, fdIndex)
        fontDictList = [fdDict]

        # Check the fontinfo file, and add any other font dicts
        srcFontInfo = os.path.dirname(self.path)
        srcFontInfo = os.path.join(srcFontInfo, "fontinfo")
        maxX = self.getUnitsPerEm() * 2
        maxY = maxX
        minY = -self.getUnitsPerEm()
        if os.path.exists(srcFontInfo):
            with open(srcFontInfo, "r", encoding="utf-8") as fi:
                fontInfoData = fi.read()
            fontInfoData = re.sub(r"#[^\r\n]+", "", fontInfoData)

            if "FDDict" in fontInfoData:
                fdGlyphDict, fontDictList, finalFDict = \
                    fdTools.parseFontInfoFile(
                        fontDictList, fontInfoData, glyphList, maxY, minY,
                        self.getPSName())
                if finalFDict is None:
                    # If a font dict was not explicitly specified for the
                    # output font, use the first user-specified font dict.
                    fdTools.mergeFDDicts(fontDictList[1:], self.fontDict)
                else:
                    fdTools.mergeFDDicts([finalFDict], self.fontDict)

        return fdGlyphDict, fontDictList
示例#28
0
def getOptions():
	options = ACOptions()
	i = 1
	numOptions = len(sys.argv)
	while i < numOptions:
		arg = sys.argv[i]
		if options.fileList and arg[0] == "-":
			raise ACOptionParseError("Option Error: All file names must follow all other options <%s>." % arg)

		if arg == "-h":
			logMsg(__help__)
			sys.exit(0)
		elif arg == "-u":
			logMsg(__usage__)
			sys.exit(0)
		elif arg == "-all":
			options.allStems = 1
		elif arg == "-a":
			options.doAlign = 1
		elif arg == "-d":
			options.debug = 1
		elif arg == "-q":
			options.verbose = 0
		elif arg == "-o":
			i = i +1
			options.reportPath = sys.argv[i]
		elif arg == "-new":
			options.new = 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:
				with open(filePath, "r", encoding='utf-8') as gf:
					glyphString = gf.read()
			except (IOError,OSError):
				raise ACOptionParseError("Option Error: could not open glyph list file <%s>." %  filePath)
			options.glyphList += parseGlyphListArg(glyphString)
		elif arg[0] == "-":
			raise ACOptionParseError("Option Error: Unknown option <%s>." %  arg)
		else:
			arg = arg.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().
			options.fileList += [arg]
		i  += 1

	if not options.fileList:
		raise ACOptionParseError("Option Error: You must provide at least one font file path.")

	return options
示例#29
0
def PrintReports(path, h_stem_list, v_stem_list, top_zone_list, bot_zone_list):
	items = ([h_stem_list, srtCnt], [v_stem_list, srtCnt],
		     [top_zone_list, srtRevVal], [bot_zone_list, srtVal])
	atime = time.asctime()
	suffixes = (".hstm.txt", ".vstm.txt", ".top.txt", ".bot.txt")
	titles = ("Horizontal Stem List for %s on %s\n" % (path, atime),
				"Vertical Stem List for %s on %s\n" % (path, atime),
				"Top Zone List for %s on %s\n" % (path, atime),
				"Bottom Zone List for %s on %s\n" % (path, atime),
			)
	headers = ("Count\tWidth\tGlyph List\n",
			"Count\tWidth\tGlyph List\n",
			"Count\tTop Zone\tGlyph List\n",
			"Count\tBottom Zone\tGlyph List\n",
			)
	for i, item in enumerate(items):
		rep_list, sortFunc = item
		if not rep_list:
			continue
		fName = '{}{}'.format(path, suffixes[i])
		title = titles[i]
		header = headers[i]
		try:
			with open(fName, "w") as fp:
				fp.write(tounicode(title))
				fp.write(tounicode(header))
				for item in formatReport(rep_list, sortFunc):
					fp.write(tounicode(item))
				print("Wrote %s" % fName)
		except (IOError, OSError):
			print("Error creating file %s!" % fName)
示例#30
0
 def build(self, featureFile):
     path = self.temp_path(suffix=".fea")
     with open(path, "w", encoding="utf-8") as outfile:
         outfile.write(featureFile)
     font = makeTTFont()
     addOpenTypeFeatures(path, font)
     return font
示例#31
0
def main(args):
	from fontTools import configLogger
	# configure the library logger (for >= WARNING)
	configLogger()
	# comment this out to enable debug messages from mtiLib's logger
	# log.setLevel(logging.DEBUG)
	font = MockFont()
	tableTag = None
	if args[0].startswith('-t'):
		tableTag = args[0][2:]
		del args[0]
	for f in args:
		log.debug("Processing %s", f)
		table = build(open(f, 'rt', encoding="utf-8"), font, tableTag=tableTag)
		blob = table.compile(font) # Make sure it compiles
		decompiled = table.__class__()
		decompiled.decompile(blob, font) # Make sure it decompiles!

		#continue
		from fontTools.misc import xmlWriter
		tag = table.tableTag
		writer = xmlWriter.XMLWriter(sys.stdout)
		writer.begintag(tag)
		writer.newline()
		table.toXML(writer, font)
		#decompiled.toXML(writer, font)
		writer.endtag(tag)
		writer.newline()
示例#32
0
def makeGAFile(gaPath, fontPath, glyphList, fontDictList, fdGlyphDict,
               removeNotdef):
    """
    Creates a glyph alias file for each FDDict.
    These files will be used by 'mergefonts' tool.
    For documentation on the format of this file, run 'mergefonts -h'.
    """
    glyph_list = getGlyphList(fontPath, removeNotdef)

    try:
        fdIndex = fdGlyphDict[glyph_list[0]][0]  # [fdIndex value, gi]
    except KeyError:
        fdIndex = 0

    fdDict = fontDictList[fdIndex]
    lineList = [""]

    lang_group = fdDict.LanguageGroup
    if lang_group is None:
        langGroup = " 0"
    else:
        langGroup = " %s" % lang_group

    dictName = "%s_%s" % (fdDict.FontName, fdDict.DictName)

    for glyph_name in glyph_list:
        gid = glyphList.index(glyph_name)
        lineList.append("%s\t%s" % (gid, glyph_name))

    lineList.append("")
    gaText = "mergefonts %s%s%s" % (dictName, langGroup, '\n'.join(lineList))

    with open(gaPath, "wb") as gf:
        gf.write(tobytes(gaText))
示例#33
0
 def expect_designspace(self, masters, instances, expectedFile):
     master_dir = tempfile.mkdtemp()
     designspace, _ = build_designspace(
         masters, master_dir, os.path.join(master_dir, "out"), instances)
     with open(designspace, mode="r", encoding="utf-8") as f:
         actual = f.readlines()
     path, _ = os.path.split(__file__)
     expectedPath = os.path.join(path, "data", expectedFile)
     with open(expectedPath, mode="r", encoding="utf-8") as f:
         expected = f.readlines()
     if actual != expected:
         for line in difflib.unified_diff(
                 expected, actual,
                 fromfile=expectedPath, tofile=designspace):
             sys.stderr.write(line)
         self.fail("*.designspace file is different from expected")
     shutil.rmtree(master_dir)
示例#34
0
 def saveChanges(self):
     if self.font_format == "OTF":
         self.ttFont.save(self.outFilePath)
         self.ttFont.close()
     elif self.font_format == "CFF":
         data = self.ttFont["CFF "].compile(self.ttFont)
         with open(self.outFilePath, "wb") as tf:
             tf.write(data)
示例#35
0
 def build_designspace(self, masters, instances):
     master_dir = tempfile.mkdtemp()
     designspace, _ = build_designspace(masters, master_dir,
                                        os.path.join(master_dir, "out"),
                                        instances)
     with open(designspace, mode="r", encoding="utf-8") as f:
         result = f.readlines()
     shutil.rmtree(master_dir)
     return result
示例#36
0
 def _get_writer(file_or_filename, encoding):
     # returns text write method and release all resources after using
     try:
         write = file_or_filename.write
     except AttributeError:
         # file_or_filename is a file name
         f = open(
             file_or_filename,
             "w",
             encoding="utf-8" if encoding == "unicode" else encoding,
             errors="xmlcharrefreplace",
         )
         with f:
             yield f.write
     else:
         # file_or_filename is a file-like object
         # encoding determines if it is a text or binary writer
         if encoding == "unicode":
             # use a text writer as is
             yield write
         else:
             # wrap a binary writer with TextIOWrapper
             detach_buffer = False
             if isinstance(file_or_filename, io.BufferedIOBase):
                 buf = file_or_filename
             elif isinstance(file_or_filename, io.RawIOBase):
                 buf = io.BufferedWriter(file_or_filename)
                 detach_buffer = True
             else:
                 # This is to handle passed objects that aren't in the
                 # IOBase hierarchy, but just have a write method
                 buf = io.BufferedIOBase()
                 buf.writable = lambda: True
                 buf.write = write
                 try:
                     # TextIOWrapper uses this methods to determine
                     # if BOM (for UTF-16, etc) should be added
                     buf.seekable = file_or_filename.seekable
                     buf.tell = file_or_filename.tell
                 except AttributeError:
                     pass
             wrapper = io.TextIOWrapper(
                 buf,
                 encoding=encoding,
                 errors="xmlcharrefreplace",
                 newline="\n",
             )
             try:
                 yield wrapper.write
             finally:
                 # Keep the original file open when the TextIOWrapper and
                 # the BufferedWriter are destroyed
                 wrapper.detach()
                 if detach_buffer:
                     buf.detach()
示例#37
0
 def read_ttx(self, path):
     lines = []
     with open(path, "r", encoding="utf-8") as ttx:
         for line in ttx.readlines():
             # Elide ttFont attributes because ttLibVersion may change,
             # and use os-native line separators so we can run difflib.
             if line.startswith("<ttFont "):
                 lines.append("<ttFont>" + os.linesep)
             else:
                 lines.append(line.rstrip() + os.linesep)
     return lines
示例#38
0
 def read_ttx(self, path):
     lines = []
     with open(path, "r", encoding="utf-8") as ttx:
         for line in ttx.readlines():
             # Elide ttFont attributes because ttLibVersion may change,
             # and use os-native line separators so we can run difflib.
             if line.startswith("<ttFont "):
                 lines.append("<ttFont>" + os.linesep)
             else:
                 lines.append(line.rstrip() + os.linesep)
     return lines
示例#39
0
 def expect_designspace(self, masters, instances, expectedFile):
     actual = self.build_designspace(masters, instances)
     path, _ = os.path.split(__file__)
     expectedPath = os.path.join(path, "data", expectedFile)
     with open(expectedPath, mode="r", encoding="utf-8") as f:
         expected = f.readlines()
     if actual != expected:
         for line in difflib.unified_diff(expected,
                                          actual,
                                          fromfile=expectedPath,
                                          tofile="<generated>"):
             sys.stderr.write(line)
         self.fail("*.designspace file is different from expected")
示例#40
0
 def make_lexer_(file_or_path, location=None):
     if hasattr(file_or_path, "read"):
         fileobj, closing = file_or_path, False
     else:
         filename, closing = file_or_path, True
         try:
             fileobj = open(filename, "r", encoding="utf-8")
         except IOError as err:
             raise FeatureLibError(str(err), location)
     data = fileobj.read()
     filename = fileobj.name if hasattr(fileobj, "name") else "<features>"
     if closing:
         fileobj.close()
     return Lexer(data, filename)
示例#41
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 = tounicode("%s\t%s\n" % (key, value))
                fp.write(string)
    except (IOError, OSError):
        raise FontInfoParseError(
            "Error. Could not open and write file '%s'" % cidfontinfoPath)
示例#42
0
    def getfdInfo(self,
                  fontPSName,
                  inputPath,
                  allow_no_blues,
                  noFlex,
                  vCounterGlyphs,
                  hCounterGlyphs,
                  glyphList,
                  fdIndex=0):
        topDict = self.topDict
        fontDictList = []
        fdGlyphDict = None

        # Get the default fontinfo from the font's top dict.
        fdDict = self.getFontInfo(fontPSName, inputPath, allow_no_blues,
                                  noFlex, vCounterGlyphs, hCounterGlyphs,
                                  fdIndex)
        fontDictList.append(fdDict)

        # Check the fontinfo file, and add any other font dicts
        srcFontInfo = os.path.dirname(inputPath)
        srcFontInfo = os.path.join(srcFontInfo, "fontinfo")
        if os.path.exists(srcFontInfo):
            with open(srcFontInfo, "r", encoding="utf-8") as fi:
                fontInfoData = fi.read()
            fontInfoData = re.sub(r"#[^\r\n]+", "", fontInfoData)
        else:
            return fdGlyphDict, fontDictList

        if "FDDict" in fontInfoData:
            maxY = topDict.FontBBox[3]
            minY = topDict.FontBBox[1]
            blueFuzz = fdDict.BlueFuzz
            fdGlyphDict, fontDictList, finalFDict = fdTools.parseFontInfoFile(
                fontDictList, fontInfoData, glyphList, maxY, minY, fontPSName,
                blueFuzz)
            if finalFDict is None:
                # If a font dict was not explicitly specified for the
                # output font, use the first user-specified font dict.
                fdTools.mergeFDDicts(fontDictList[1:], topDict.Private)
            else:
                fdTools.mergeFDDicts([finalFDict], topDict.Private)
        return fdGlyphDict, fontDictList
示例#43
0
def collect_features_content(instances, inst_idx_lst):
    """
    Returns a dictionary whose keys are 'features.fea' file paths, and the
    values are the contents of the corresponding file.
    """
    fea_dict = {}
    for i, inst_dscrpt in enumerate(instances):
        if inst_idx_lst and i not in inst_idx_lst:
            continue
        ufo_pth = inst_dscrpt.path
        if ufo_pth is None:
            continue
        ufo_pth = os.path.abspath(os.path.realpath(ufo_pth))
        fea_pth = os.path.join(ufo_pth, FEATURES_FILENAME)
        if os.path.isfile(fea_pth):
            with open(fea_pth, 'rb') as fp:
                fea_cntnts = fp.read()
            fea_dict[fea_pth] = fea_cntnts
    return fea_dict
示例#44
0
def parseCounterHintData(path):
	hCounterGlyphList = []
	vCounterGlyphList = []
	gf = open(path, "rt")
	data = gf.read()
	gf.close()
	lines = re.findall(r"([^\r\n]+)", data)
	# strip blank and comment lines
	lines = filter(lambda line: re.sub(r"#.+", "", line), lines)
	lines = filter(lambda line: line.strip(), lines)
	for line in lines:
		fields = line.split()
		if (len(fields) != 2) or (fields[0] not in ["V", "v", "H", "h"]) :
			print("\tError: could not process counter hint line '%s' in file %s. Doesn't look like V or H followed by a tab or space, and then a glyph name." % (line, path))
		elif  fields[0] in ["V", "v"]:
			vCounterGlyphList.append(fields[1])
		else:
			hCounterGlyphList.append(fields[1])
	return hCounterGlyphList, vCounterGlyphList
示例#45
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] + "\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)
示例#46
0
def checkFontinfoFile(options):
	# Check if there ia a makeotf fontinfo file in the input font directory. If so,
	# get any Vcounter or HCouunter glyphs from it.
	srcFontInfo = os.path.dirname(options.inputPath)
	srcFontInfo = os.path.join(srcFontInfo, "fontinfo")
	if os.path.exists(srcFontInfo):
		fi = open(srcFontInfo, "r")
		data = fi.read()
		fi.close()
		data = re.sub(r"#[^\r\n]+", "", data)
		counterGlyphLists = re.findall(r"([VH])CounterChars\s+\(\s*([^\)\r\n]+)\)", data)
		for entry in counterGlyphLists:
			glyphList = entry[1].split()
			if glyphList:
				if entry[0] == "V":
					options.vCounterGlyphs.extend(glyphList)
				else:
					options.hCounterGlyphs.extend(glyphList)

		if 	options.vCounterGlyphs or options.hCounterGlyphs:
			options.counterHintFile = srcFontInfo
示例#47
0
 def expect_designspace(self, masters, instances, expectedFile):
     actual = self.build_designspace(masters, instances)
     path, _ = os.path.split(__file__)
     expectedPath = os.path.join(path, "data", expectedFile)
     with open(expectedPath, mode="r", encoding="utf-8") as f:
         expected = f.readlines()
     if os.path.sep == '\\':
         # On windows, the test must not fail because of a difference between
         # forward and backward slashes in filname paths.
         # The failure happens because of line 217 of "mutatorMath\ufo\document.py"
         # > pathRelativeToDocument = os.path.relpath(fileName, os.path.dirname(self.path))
         expected = [
             line.replace('filename="out/', 'filename="out\\')
             for line in expected
         ]
     if actual != expected:
         for line in difflib.unified_diff(expected,
                                          actual,
                                          fromfile=expectedPath,
                                          tofile="<generated>"):
             sys.stderr.write(line)
         self.fail("*.designspace file is different from expected")
示例#48
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
示例#49
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
示例#50
0
文件: lexer.py 项目: RoelN/fonttools
 def make_lexer_(filename, location):
     try:
         with open(filename, "r", encoding="utf-8") as f:
             return Lexer(f.read(), filename)
     except IOError as err:
         raise FeatureLibError(str(err), location)
示例#51
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)
示例#52
0
def test_localisedNames(tmpdir):
    tmpdir = str(tmpdir)
    testDocPath = os.path.join(tmpdir, "testLocalisedNames.designspace")
    testDocPath2 = os.path.join(tmpdir, "testLocalisedNames_roundtrip.designspace")
    masterPath1 = os.path.join(tmpdir, "masters", "masterTest1.ufo")
    masterPath2 = os.path.join(tmpdir, "masters", "masterTest2.ufo")
    instancePath1 = os.path.join(tmpdir, "instances", "instanceTest1.ufo")
    instancePath2 = os.path.join(tmpdir, "instances", "instanceTest2.ufo")
    doc = DesignSpaceDocument()
    # add master 1
    s1 = SourceDescriptor()
    s1.filename = os.path.relpath(masterPath1, os.path.dirname(testDocPath))
    s1.name = "master.ufo1"
    s1.copyInfo = True
    s1.location = dict(weight=0)
    doc.addSource(s1)
    # add master 2
    s2 = SourceDescriptor()
    s2.filename = os.path.relpath(masterPath2, os.path.dirname(testDocPath))
    s2.name = "master.ufo2"
    s2.location = dict(weight=1000)
    doc.addSource(s2)
    # add instance 1
    i1 = InstanceDescriptor()
    i1.filename = os.path.relpath(instancePath1, os.path.dirname(testDocPath))
    i1.familyName = "Montserrat"
    i1.styleName = "SemiBold"
    i1.styleMapFamilyName = "Montserrat SemiBold"
    i1.styleMapStyleName = "Regular"
    i1.setFamilyName("Montserrat", "fr")
    i1.setFamilyName(u"モンセラート", "ja")
    i1.setStyleName("Demigras", "fr")
    i1.setStyleName(u"半ば", "ja")
    i1.setStyleMapStyleName(u"Standard", "de")
    i1.setStyleMapFamilyName("Montserrat Halbfett", "de")
    i1.setStyleMapFamilyName(u"モンセラート SemiBold", "ja")
    i1.name = "instance.ufo1"
    i1.location = dict(weight=500, spooky=666)  # this adds a dimension that is not defined.
    i1.postScriptFontName = "InstancePostscriptName"
    glyphData = dict(name="arrow", mute=True, unicodes=[0x123])
    i1.glyphs['arrow'] = glyphData
    doc.addInstance(i1)
    # now we have sources and instances, but no axes yet.
    doc.axes = []   # clear the axes
    # write some axes
    a1 = AxisDescriptor()
    a1.minimum = 0
    a1.maximum = 1000
    a1.default = 0
    a1.name = "weight"
    a1.tag = "wght"
    # note: just to test the element language, not an actual label name recommendations.
    a1.labelNames[u'fa-IR'] = u"قطر"
    a1.labelNames[u'en'] = u"Wéíght"
    doc.addAxis(a1)
    a2 = AxisDescriptor()
    a2.minimum = 0
    a2.maximum = 1000
    a2.default = 0
    a2.name = "width"
    a2.tag = "wdth"
    a2.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)]
    a2.labelNames[u'fr'] = u"Poids"
    doc.addAxis(a2)
    # add an axis that is not part of any location to see if that works
    a3 = AxisDescriptor()
    a3.minimum = 333
    a3.maximum = 666
    a3.default = 444
    a3.name = "spooky"
    a3.tag = "spok"
    a3.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)]
    #doc.addAxis(a3)    # uncomment this line to test the effects of default axes values
    # write some rules
    r1 = RuleDescriptor()
    r1.name = "named.rule.1"
    r1.conditionSets.append([
        dict(name='weight', minimum=200, maximum=500),
        dict(name='width', minimum=0, maximum=150)
    ])
    r1.subs.append(("a", "a.alt"))
    doc.addRule(r1)
    # write the document
    doc.write(testDocPath)
    assert os.path.exists(testDocPath)
    # import it again
    new = DesignSpaceDocument()
    new.read(testDocPath)
    new.write(testDocPath2)
    with open(testDocPath, 'r', encoding='utf-8') as f1:
        t1 = f1.read()
    with open(testDocPath2, 'r', encoding='utf-8') as f2:
        t2 = f2.read()
    assert t1 == t2
示例#53
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()))
示例#54
0
]

path = os.path.dirname(__file__)

# =======
# = AGD =
# =======

unicode2name_AGD = {}
name2unicode_AGD = {}

AGDPath = os.path.join(path, "AGD.txt")

if os.path.exists(AGDPath):
    f = open(AGDPath, "r")
    lines = f.readlines()
    f.close()

    # format
    # <glyphName>
    # <tab> <tag>: <value>

    currentGlyphName = None
    for line in lines:
        if line.startswith("\t") and currentGlyphName is not None:
            tag, value = line.split(":")
            tag = tag.strip()
            value = value.strip()
            if tag == "uni":
                value = int(value, 16)
示例#55
0
def get_font_format(font_file_path):
    with open(font_file_path, "rb") as f:
        head = f.read(4).decode()
        if head in ("\0\1\0\0", "true"):
            return "TTF"
        return None
示例#56
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()))
示例#57
0
 def SaveToFile(self, filename):
     with open(filename, 'wb') as fileobj:
         self.SaveToFileObject(fileobj)
示例#58
0
def read_txt_file_lines(file_path):
    with open(file_path, "r", encoding="utf-8") as f:
        return f.read().splitlines()