Exemplo n.º 1
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)
Exemplo n.º 2
0
def test_remove_overlap_otf():
    actual_path = get_temp_file_path()
    copy2(get_input_path('font.otf'), actual_path)
    runner(CMD + ['-f', actual_path, '-o', 'e', 'q'])
    actual_ttx = generate_ttx_dump(actual_path, ['CFF '])
    expected_ttx = get_expected_path('font.ttx')
    assert differ([expected_ttx, actual_ttx, '-s', '<ttFont sfntVersion'])
Exemplo n.º 3
0
def test_cef_cefsvg():
    font_path = get_input_path('cff2_vf.otf')
    output_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', 'cef', 'cefsvg', 'cr', 'gn1', 'abs', 'sa',
                  '-f', font_path, output_path])
    expected_path = get_expected_path('cef_cefsvg_cr.svg')
    assert differ([expected_path, output_path])
Exemplo n.º 4
0
def filterDesignspaceInstances(dsDoc, options):
    """
    - Filter unwanted instances out of dsDoc as specified by -i option
      (options.indexList), which has already been validated.
    - Promote dsDoc.instance.paths to absolute, referring to original
      dsDoc's location.
    - Remove any existing instance
    - Write the modified doc to a proper temp file
    - Return the path to the temp DS file.
    """

    origDSPath = options.dsPath
    filteredInstances = []

    for idx in sorted(options.indexList):
        instance = dsDoc.instances[idx]
        instance.path = os.path.abspath(
            os.path.realpath(os.path.join(
                origDSPath,
                instance.path,
            )))

        if os.path.exists(instance.path):
            glyphDir = os.path.join(instance.path, "glyphs")
            if os.path.exists(glyphDir):
                shutil.rmtree(glyphDir, ignore_errors=True)

        filteredInstances.append(instance)

    dsDoc.instances = filteredInstances
    tmpPath = get_temp_file_path()
    dsDoc.write(tmpPath)

    return tmpPath
Exemplo n.º 5
0
def generate_ps_dump(font_path):
    with open(font_path, 'rb') as ps_file:
        data = ps_file.read()
    line = ''
    i = 0
    in_binary_section = False
    bytes_read = 0
    byte_count = 0
    temp_path = get_temp_file_path()
    with open(temp_path, 'w') as temp_file:
        while i < len(data):
            x = data[i]
            if not in_binary_section:
                if x != 0x0A:
                    line += '%c' % x
                else:
                    if line.startswith('%%BeginData'):
                        in_binary_section = True
                        byte_count = int(line.split()[1])
                    line += '\n'
                    temp_file.write(line)
                    line = ''
            else:
                bytes_read += 1
                if bytes_read == byte_count:
                    in_binary_section = False
                    if bytes_read % 32 != 1:
                        temp_file.write('\n')
                else:
                    temp_file.write('%02X' % x)
                    if bytes_read % 32 == 0:
                        temp_file.write('\n')
            i += 1
    return temp_path
Exemplo n.º 6
0
def test_date_and_time_pdf():
    """
    test the use of date and time functions in pdfwrite.c
    """
    input_path = get_input_path('font.otf')
    output_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', 'pdf', '-f', input_path, output_path])
    now = time.time()
    tz = time.timezone
    tz_hr = abs(int(tz / 3600))  # ignore sign since we're splitting on +/-
    tz_min = (tz % 3600) // 60
    with open(output_path) as output_file:
        lines = output_file.readlines()
        creation_date_str = re.split(r'[()]', lines[13])[1]
        mod_date_str = re.split(r'[()]', lines[14])[1]
        assert (creation_date_str == mod_date_str)
        (date_time_str, tz_hr_str, tz_min_str) = \
            re.split(r"[:+\-Z']", creation_date_str)[1:4]
        creation_time = time.mktime(
            time.strptime(date_time_str, '%Y%m%d%H%M%S'))
        hours_diff = abs(now - creation_time) / 3600
        assert (hours_diff < 1)
        creation_tz_hr = int(tz_hr_str)
        assert (creation_tz_hr == tz_hr)
        creation_tz_min = int(tz_min_str)
        assert (creation_tz_min == tz_min)
        file_date_str = re.split(r"[():]", lines[36])[2].strip()
        file_time_str = re.split(r"[() ]", lines[38])[3]
        file_date_time_str = file_date_str + ' ' + file_time_str
        file_time = time.mktime(
            time.strptime(file_date_time_str, "%d %b %y %H:%M"))
        hours_diff = abs(now - file_time) / 3600
        assert (hours_diff < 1)
Exemplo n.º 7
0
def test_skip_ufo3_global_guides_bug700():
    input_filename = "bug700.ufo"
    actual_path = get_temp_file_path()
    runner(CMD + [
        '-o', 'f', f'_{get_input_path(input_filename)}', 'o', f'_{actual_path}'
    ])
    assert font_has_table(actual_path, 'CFF ')
Exemplo n.º 8
0
def test_write_fdselect_format_4():
    font_name = 'FDArrayTest257FontDicts.otf'
    input_path = get_input_path(font_name)
    output_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', 'cff2', '-f', input_path, output_path])
    expected_path = get_expected_path('FDArrayTest257FontDicts.cff2')
    assert differ([expected_path, output_path, '-m', 'bin'])
Exemplo n.º 9
0
def test_recalculate_font_bbox_bug618(to_format, args, exp_filename):
    font_path = get_input_path('bug618.pfa')
    save_path = get_temp_file_path()

    runner(CMD + ['-f', font_path, save_path, '-o', to_format] + args)

    file_ext = to_format
    if to_format == 't1':
        file_ext = 'pfa'
    elif to_format == 'afm':
        file_ext = 'txt'

    expected_path = get_expected_path(f'bug618/{exp_filename}.{file_ext}')

    diff_mode = []
    if to_format == 'cff':
        diff_mode = ['-m', 'bin']

    skip = []
    if to_format == 'afm':
        skip = [
            '-s', 'Comment Creation Date:' + SPLIT_MARKER + 'Comment Copyright'
        ]
    elif to_format == 't1':
        skip = ['-s'] + PFA_SKIP[:]

    assert differ([expected_path, save_path] + diff_mode + skip)
Exemplo n.º 10
0
def test_read_fdselect_format_4(option):
    font_name = 'fdselect4.otf'
    input_path = get_input_path(font_name)
    output_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', option, '-f', input_path, output_path])
    expected_path = get_expected_path(font_name + '.' + option)
    assert differ([expected_path, output_path, '-s', '## Filename'])
Exemplo n.º 11
0
def test_overlap_removal():
    input_path = get_input_path('overlaps.ufo')
    expected_path = get_expected_path('overlaps.pfa')
    output_path = get_temp_file_path()
    args = [TOOL, '-t1', '+V', '-o', output_path, input_path]
    subprocess.call(args)
    assert differ([expected_path, output_path, '-s', PFA_SKIP[0]])
Exemplo n.º 12
0
def test_cff2_extract(args, exp_filename):
    # read CFF2 VF, write CFF2 table
    font_path = get_input_path('SourceCodeVariable-Roman.otf')
    cff2_path = get_temp_file_path()
    runner(CMD + ['-a', '-f', font_path, cff2_path, '-o', 'cff2'] + args)
    expected_path = get_expected_path(exp_filename)
    assert differ([expected_path, cff2_path, '-m', 'bin'])
Exemplo n.º 13
0
def test_ttread_varinst():
    font_path = get_input_path('AdobeVFPrototype.ttf')
    save_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', '3', 'g', '_A', 'U', '_500,800',
                  '-f', font_path, save_path])
    expected_path = get_expected_path('vfproto_tt_inst500_800.txt')
    assert differ([expected_path, save_path, '-s', '## Filename'])
Exemplo n.º 14
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
Exemplo n.º 15
0
def test_multiple_inputs_fail():
    path1 = get_input_path('latincid.otf')
    path2 = get_input_path('sans.otf')
    out_path = get_temp_file_path()
    with pytest.raises(SystemExit) as exc_info:
        otf2ttf(['-o', out_path, path1, path2])
    assert exc_info.value.code == 2
Exemplo n.º 16
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
def test_componentize():
    ttf_path = _get_test_ttf_path()
    save_path = get_temp_file_path()
    opts = Object()
    setattr(opts, 'font_path', ttf_path)
    setattr(opts, 'output_path', save_path)
    ufo, ps_names = ttfcomp.get_glyph_names_mapping(_get_test_ufo_path())
    ttcomp_obj = ttfcomp.TTComponentizer(ufo, ps_names, opts)
    ttcomp_obj.componentize()

    # 'get_composites_data' method
    comps_data = ttcomp_obj.composites_data
    comps_name_list = sorted(comps_data.keys())
    comps_comp_list = [comps_data[gname] for gname in comps_name_list]
    assert comps_name_list == [
        'aa', 'aacute', 'adieresis', 'atilde', 'uni01CE'
    ]
    assert comps_comp_list[1].names == ('a', 'uni0301')
    assert comps_comp_list[4].names == ('a', 'uni030C')
    assert comps_comp_list[1].positions == ((0, 0), (263.35, 0))
    assert comps_comp_list[4].positions == ((0, 0), (263, 0))

    # 'assemble_components' method
    comps_data = ttfcomp.ComponentsData()
    comps_data.names = ('a', 'uni01CE')
    comps_data.positions = ((0, 0), (263, 0))
    comps_data.same_advwidth = True
    comp_one, comp_two = ttcomp_obj.assemble_components(comps_data)
    assert comp_one.glyphName == 'a'
    assert comp_two.glyphName == 'uni01CE'
    assert (comp_one.x, comp_one.y) == (0, 0)
    assert (comp_two.x, comp_two.y) == (263, 0)
    assert comp_one.flags == 0x204
    assert comp_two.flags == 0x4
Exemplo n.º 18
0
def test_lib_removes_outlines_bug1366():
    input_path = get_input_path("bug1366.ufo")
    expected_path = get_expected_path("bug1366.pfa")
    output_path = get_temp_file_path()
    subprocess.call([TOOL, '-t1', '-o', output_path, input_path])
    expected_path = generate_ps_dump(expected_path)
    output_path = generate_ps_dump(output_path)
    assert differ([expected_path, output_path, '-s', PFA_SKIP[0]])
Exemplo n.º 19
0
def test_build_options_cs_cl_bug459(args, input_filename, ttx_filename):
    actual_path = get_temp_file_path()
    runner(CMD + [
        '-o', 'f', f'_{get_input_path(input_filename)}', 'o', f'_{actual_path}'
    ] + args)
    actual_ttx = generate_ttx_dump(actual_path, ['cmap'])
    expected_ttx = get_expected_path(ttx_filename)
    assert differ([expected_ttx, actual_ttx, '-s', '<ttFont sfntVersion'])
def test_run_invalid_ufo():
    ttf_path = _get_test_ttf_path()
    temp_dir = get_temp_dir_path()
    save_path = get_temp_file_path(directory=temp_dir)
    ufo_path = save_path + '.ufo'
    copy2(ttf_path, save_path)
    copy2(ttf_path, ufo_path)
    assert ttfcomp.main([save_path]) == 1
def test_run_cli_with_output_path():
    actual_path = get_temp_file_path()
    runner(CMD + [
        '-o', 'o', f'_{actual_path}', f'_{get_input_path(TEST_TTF_FILENAME)}'
    ])
    actual_ttx = generate_ttx_dump(actual_path, ['maxp', 'glyf'])
    expected_ttx = get_expected_path('ttfcomponentizer.ttx')
    assert differ([expected_ttx, actual_ttx, '-s', '<ttFont sfntVersion'])
Exemplo n.º 22
0
def generate_spot_dumptables(font_path, tables):
    tmp_txt_path = get_temp_file_path()
    myargs = ['spot', "-t" + ",".join(tables), font_path]
    spot_txt = subprocess.check_output(myargs, timeout=TIMEOUT)
    tf = open(tmp_txt_path, "wb")
    tf.write(spot_txt)
    tf.close()
    return tmp_txt_path
Exemplo n.º 23
0
def test_run_with_output_path():
    ttf_path = _get_test_ttf_path()
    save_path = get_temp_file_path()
    ttfdecomp.main(['-o', save_path, ttf_path])
    font = TTFont(save_path)
    gtable = font['glyf']
    composites = [gtable[gl].isComposite() for gl in font.glyphOrder]
    assert not any(composites)
def test_run_with_output_path():
    ttf_path = _get_test_ttf_path()
    save_path = get_temp_file_path()
    ttfcomp.main(['-o', save_path, ttf_path])
    gtable = TTFont(save_path)['glyf']
    composites = [
        gname for gname in gtable.glyphs if (gtable[gname].isComposite())
    ]
    assert sorted(composites) == ['aa', 'aacute', 'uni01CE']
Exemplo n.º 25
0
def test_feature_includes_ufo_bug164():
    input_filename = "bug164/d1/d2/font.ufo"
    otf_path = get_temp_file_path()

    runner(
        CMD +
        ['-o', 'f', f'_{get_input_path(input_filename)}', 'o', f'_{otf_path}'])

    assert font_has_table(otf_path, 'head')
Exemplo n.º 26
0
def test_remove_hints_bug180():
    font_path = get_input_path('cid.otf')
    cid_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', 't1', 'n', '-f', font_path, cid_path])
    expected_path = get_expected_path('cid_nohints.ps')
    expected_path = generate_ps_dump(expected_path)
    actual_path = generate_ps_dump(cid_path)
    skip = ['-s'] + PS_SKIP2
    assert differ([expected_path, actual_path] + skip)
Exemplo n.º 27
0
def test_dcf_with_infinite_recursion_bug775():
    font_path = get_bad_input_path('subr_test_font_infinite_recursion.otf')
    dcf_path = get_temp_file_path()
    with pytest.raises(subprocess.CalledProcessError) as err:
        runner(CMD + ['-a', '-o', 'dcf', '-f', font_path, dcf_path])
    assert(err.value.returncode == 1)  # exit code of 1, not segfault of -11
    expected_path = get_expected_path(
        'subr_test_font_infinite_recursion.dcf.txt')
    assert differ([expected_path, dcf_path])
Exemplo n.º 28
0
def test_V_option(arg, exp_filename):
    input_path = get_input_path('overlap.pfa')
    expected_path = get_expected_path(f'overlap_{exp_filename}.pfa')
    output_path = get_temp_file_path()
    args = [TOOL, '-t1', '-o', output_path, input_path]
    if arg:
        args.insert(2, arg)
    subprocess.call(args)
    assert differ([expected_path, output_path, '-s', PFA_SKIP[0]])
Exemplo n.º 29
0
def test_cff2_no_vf_bug353():
    # read CFF2 WITHOUT VF info, write a CFF2 out. 'regular_CFF2.otf'
    # is derived by taking the regular.otf file from the sfntdiff
    # 'input_data' directory, and converting the CFF table to CFF2.
    font_path = get_input_path('regular_CFF2.otf')
    cff2_path = get_temp_file_path()
    runner(CMD + ['-a', '-o', 'cff2', '-f', font_path, cff2_path])
    expected_path = get_expected_path('regular_CFF2.cff2')
    assert differ([expected_path, cff2_path, '-m', 'bin'])
Exemplo n.º 30
0
def test_script_file(dcf_dump_level):
    font_path = get_input_path('cid.otf')
    opts_path = get_temp_file_path()
    opts_file_content = f'\n# foo\n # bar\r -{dcf_dump_level}\t"{font_path}"'
    with open(opts_path, 'a') as fp:
        fp.write(opts_file_content)
    actual_path = runner(CMD + ['-s', '-a', '-o', 'dcf', 's', '-f', opts_path])
    expected_path = get_expected_path(f'cid_dcf_{dcf_dump_level}.txt')
    assert differ([expected_path, actual_path])
Exemplo n.º 31
0
def test_stdin():
    input_path = get_input_path('type1.pfa')
    expected_path = get_expected_path('stdin.txt')
    output_path = get_temp_file_path()
    with open(input_path) as fp:
        output = subprocess.check_output([TOOL], stdin=fp)
    with open(output_path, 'wb') as fp:
        fp.write(output)
    assert differ([expected_path, output_path])
Exemplo n.º 32
0
def test_beztools_hhint_over_limit_bug629():
    test_filename = 'bug629.pfa'
    actual_path = get_temp_file_path()
    expected_path = get_expected_path(test_filename)
    runner(CMD + ['-o', 'nb', 'o', f'_{actual_path}', '-f', test_filename])
    assert differ([
        expected_path, actual_path, '-s',
        r'%ADOt1write' + SPLIT_MARKER + r'%%Copyright: Copyright'
    ])
Exemplo n.º 33
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
Exemplo n.º 34
0
def main():
    args = sys.argv

    if len(args) >= 2:
        inputPath = args[1]
        outputPath = fdkutils.get_temp_file_path()

        fontinfoPath = None
        if len(args) == 3:
            fontinfoPath = args[2]

        convertFontToCID(inputPath, outputPath, fontinfoPath)

        save_path = '{}{}'.format(os.path.splitext(inputPath)[0], '-CID.ps')

        if os.path.isfile(outputPath):
            os.rename(outputPath, save_path)
    else:
        print('ERROR: Missing path to font to convert.')
Exemplo n.º 35
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)
Exemplo n.º 36
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()))
Exemplo n.º 37
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()))
Exemplo n.º 38
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)