Ejemplo n.º 1
0
#Needs: fonts/Ambrosia.sfd

#Test the fontforge module (but not its types)
import sys, fontforge

foo = fontforge.getPrefs("DetectDiagonalStems")
fontforge.setPrefs("DetectDiagonalStems",~foo)
fontforge.loadPrefs()
# fontforge.savePrefs()
fontforge.defaultOtherSubrs()
# fontforge.readOtherSubrsFile()

foo = fontforge.hasSpiro()

# fontforge.loadEncodingFile()
# fontforge.loadNamelist()
# fontforge.loadNamelistDir()
# fontforge.preloadCidmap()

fontforge.printSetup("lpr")

if (fontforge.unicodeFromName("A")!=65) or (fontforge.unicodeFromName("uni030D")!=0x30D):
  raise ValueError("Wrong return from unicodeFromName")

foo = fontforge.version()

ambrosia = sys.argv[1]

fonts = fontforge.fonts()
if ( len(fonts)!=0 ) :
  raise ValueError("Wrong return from fontforge.fonts")
Ejemplo n.º 2
0
def execute(tool, fn, argspec, chain = None):
    # Function to handle parameter parsing, font and file opening etc in command-line scripts
    # Supports opening (and saving) fonts using FontForge (FF), PysilFont UFO (UFO) or fontTools (FT)
    # Special handling for:
    #   -d  variation on -h to print extra info about defaults
    #   -q  quiet mode - suppresses progress messages and sets screen logging to errors only
    #   -l  opens log file and also creates a logger function to write to the log file
    #   -p  other parameters. Includes backup settings and loglevel/scrlevel settings for logger
    #       for UFOlib scripts, also includes all outparams keys and ufometadata settings
    # infont and returnfont are used when chaining calls to execute together, passing ifont on without writing to disk

    params = chain["params"] if chain else parameters()
    logger = chain["logger"] if chain else params.logger  # paramset has already created a basic logger
    argv   = chain["argv"]   if chain else sys.argv

    if tool == "FF":
        import fontforge
        if fontforge.hasUserInterface():
            return  # Execute is for command-line use
        fontforge.loadPrefs()
        fontforge.setPrefs("PreserveTables", "DSIG,Feat,Glat,Gloc,LTSH,Silf,Sill,Silt,VDMX,hdmx")  ## Perhaps should be a parameter and check for existing values
    elif tool == "UFO":
        from silfont.ufo import Ufont
    elif tool == "FT":
        from fontTools import ttLib
    elif tool == "" or tool is None:
        tool = None
    else:
        logger.log("Invalid tool in call to execute()", "X")
        return
    basemodule = sys.modules[fn.__module__]
    poptions = {}
    poptions['prog'] = splitfn(argv[0])[1]
    poptions['description'] = basemodule.__doc__
    poptions['formatter_class'] = argparse.RawDescriptionHelpFormatter
    epilog = "For more help see https://github.com/silnrsi/pysilfont/blob/master/docs/scripts.md#" + poptions['prog'] + "\n\n"
    poptions['epilog'] = epilog + "Version: " + params.sets['default']['version'] + "\n" + params.sets['default']['copyright']

    parser = argparse.ArgumentParser(**poptions)
    parser._optionals.title = "other arguments"

    # Add standard arguments
    standardargs = [
            ('-d', '--defaults', {'help': 'Display help with info on default values', 'action': 'store_true'}, {}), 
            ('-q', '--quiet', {'help': 'Quiet mode - only display errors', 'action': 'store_true'}, {}), 
            ('-l', '--log', {'help': 'Log file'}, {'type': 'outfile'}), 
            ('-p', '--params', {'help': 'Other parameters', 'action': 'append'}, {'type': 'optiondict'})]
    standardargsindex = ['defaults', 'quiet', 'log', 'params']

    suppliedargs = []
    for a in argspec:
        argn = a[:-2][-1]  # [:-2] will give either 1 or 2, the last of which is the full argument name
        if argn[0:2] == "--": argn = argn[2:]  # Will start with -- for options
        suppliedargs.append(argn)
    for i, arg in enumerate(standardargsindex):
        if arg not in suppliedargs: argspec.append(standardargs[i])

    # Special handling for "-d" to print default value info with help text
    defhelp = False
    if "-d" in argv:
        defhelp = True
        pos = argv.index("-d")
        argv[pos] = "-h"  # Set back to -h for argparse to recognise
        deffiles = []
        defother = []

    quiet = True if "-q" in argv else False
    if quiet: logger.scrlevel = "E"

    # Process the supplied argument specs, add args to parser, store other info in arginfo
    arginfo = []
    logdef = None
    for a in argspec:
        # Process all but last tuple entry as argparse arguments
        nonkwds = a[:-2]
        kwds = a[-2]
        parser.add_argument(*nonkwds, **kwds)
        # Create dict of framework keywords using argument name
        argn = nonkwds[-1]  # Find the argument name from first 1 or 2 tuple entries
        if argn[0:2] == "--": argn = argn[2:]  # Will start with -- for options
        ainfo=a[-1]
        ainfo['name']=argn
        if argn == 'log':
            logdef = ainfo['def'] if 'def' in ainfo else None
        arginfo.append(ainfo)
        if defhelp:
            arg = nonkwds[0]
            if 'def' in ainfo:
                deffiles.append([arg, ainfo['def']])
            elif 'default' in kwds:
                defother.append([arg, kwds['default']])

    # if -d specified, change the help epilog to info about argument defaults
    if defhelp:
        if not (deffiles or defother):
            deftext = "No defaults for parameters/options"
        else:
            deftext = "Defaults for parameters/options - see user docs for details\n"
        if deffiles:
            deftext = deftext + "\n  Font/file names\n"
            for (param, defv) in deffiles:
                deftext = deftext + '    {:<20}{}\n'.format(param, defv)
        if defother:
            deftext = deftext + "\n  Other parameters\n"
            for (param, defv) in defother:
                deftext = deftext + '    {:<20}{}\n'.format(param, defv)
        parser.epilog = deftext + "\n\n" + parser.epilog

    # Parse the command-line arguments. If errors or -h used, procedure will exit here
    args = parser.parse_args(argv[1:])

    # Process the first positional parameter to get defaults for file names
    fppval = getattr(args, arginfo[0]['name'])
    if fppval is None: fppval = ""  # For scripts that can be run with no positional parameters
    (fppath, fpbase, fpext) = splitfn(fppval)  # First pos param use for defaulting

    # Process parameters
    if chain:
        execparams = params.sets["main"]
        args.params = {}  # clparams not used when chaining
    else:
        # Read config file from disk if it exists
        configname = os.path.join(fppath, "pysilfont.cfg")
        if os.path.exists(configname):
            params.addset("config file", configname, configfile=configname)
        else:
            params.addset("config file")  # Create empty set
        if not quiet and "scrlevel" in params.sets["config file"]: logger.scrlevel = params.sets["config file"]["scrlevel"]

        # Process command-line parameters
        clparams = {}
        if 'params' in args.__dict__:
            if args.params is not None:
                for param in args.params:
                    x = param.split("=", 1)
                    if len(x) != 2:
                        logger.log("params must be of the form 'param=value'", "S")
                    if x[1] == "\\t": x[1] = "\t"  # Special handling for tab characters
                    clparams[x[0]] = x[1]

        args.params = clparams
        params.addset("command line", "command line", inputdict=clparams)
        if not quiet and "scrlevel" in params.sets["command line"]: logger.scrlevel = params.sets["command line"]["scrlevel"]

        # Create main set of parameters based on defaults then update with config file values and command line values
        params.addset("main", copyset="default")
        params.sets["main"].updatewith("config file")
        params.sets["main"].updatewith("command line")
        execparams = params.sets["main"]

    # Set up logging
    if chain:
        setattr(args, 'logger', logger)
        args.logfile = logger.logfile
    else:
        logfile = None
        if 'log' in args.__dict__:
            logname = args.log if args.log else ""
            if logdef is not None:
                (path, base, ext) = splitfn(logname)
                (dpath, dbase, dext) = splitfn(logdef)
                if not path:
                    if base and ext:  # If both specified then use cwd, ie no path
                        path = ""
                    else:
                        path = (fppath if dpath is "" else os.path.join(fppath, dpath))
                if not base:
                    if dbase == "":
                        base = fpbase
                    elif dbase[0] == "_":  # Append to font name if starts with _
                        base = fpbase + dbase
                    else:
                        base = dbase
                if not ext and dext: ext = dext
                logname = os.path.join(path, base+ext)
            if logname == "":
                logfile = None
            else:
                (logname, logpath, exists) = fullpath(logname)
                if not exists:
                    logger.log("Log file directory " + logpath + " does not exist", "S")
                if not quiet: logger.log('Opening log file for output: ' + logname, "P")
                try:
                    logfile = open(logname, "w")
                except Exception as e:
                    print e
                    sys.exit(1)
                args.log = logfile
        # Set up logger details
        logger.loglevel = execparams['loglevel'].upper()
        if not quiet: logger.scrlevel = execparams['scrlevel'].upper()
        logger.logfile = logfile
        setattr(args, 'logger', logger)

# Process the argument values returned from argparse

    outfont = None
    infontlist = []
    for c, ainfo in enumerate(arginfo):
        aval = getattr(args, ainfo['name'])
        if ainfo['name'] in ('params', 'log'): continue  # params and log already processed
        atype = None
        adef = None
        if 'type' in ainfo:
            atype = ainfo['type']
            if atype not in ('infont', 'outfont', 'infile', 'outfile', 'incsv', 'filename', 'optiondict'):
                logger.log("Invalid type of " + atype + " supplied in argspec", "X")
            if atype != 'optiondict':  # All other types are file types, so adef must be set, even if just to ""
                adef = ainfo['def'] if 'def' in ainfo else ""
            if adef is None and aval is None:  # If def explicitly set to None then this is optional
                setattr(args, ainfo['name'], None)
                continue

        if c == 0:
            if aval is None : logger.log("Invalid first positional parameter spec", "X")
            if aval[-1] in ("\\","/"): aval = aval[0:-1]  # Remove trailing slashes
        else:  #Handle defaults for all but first positional parameter
            if adef is not None:
                if not aval: aval = ""
                if aval == "" and adef == "":  # Only valid for output font parameter
                    if atype != "outfont":
                        logger.log("No value suppiled for " + ainfo['name'], "S")
                        ## Not sure why this needs to fail - we need to cope with other optional file or filename parameters
                (apath, abase, aext) = splitfn(aval)
                (dpath, dbase, dext) = splitfn(adef)  # dpath should be None
                if not apath:
                    if abase and aext:  # If both specified then use cwd, ie no path
                        apath = ""
                    else:
                        apath = fppath
                if not abase:
                    if dbase == "":
                        abase = fpbase
                    elif dbase[0] == "_":  # Append to font name if starts with _
                        abase = fpbase + dbase
                    else:
                        abase = dbase
                if not aext:
                    if dext:
                        aext = dext
                    elif (atype == 'outfont' or atype == 'infont'): aext = fpext
                aval = os.path.join(apath, abase+aext)

        # Open files/fonts
        if atype == 'infont':
            if tool is None:
                logger.log("Can't specify a font without a font tool", "X")
            infontlist.append((ainfo['name'], aval))  # Build list of fonts to open when other args processed
        elif atype == 'infile':
            if not quiet: logger.log('Opening file for input: '+aval, "P")
            try:
                aval = open(aval, "r")
            except Exception as e:
                print e
                sys.exit(1)
        elif atype == 'incsv':
            if not quiet: logger.log('Opening file for input: '+aval, "P")
            aval = csvreader(aval)
        elif atype == 'outfile':
            (aval, path, exists) = fullpath(aval)
            if not exists:
                logger.log("Output file directory " + path + " does not exist", "S")
            if not quiet: logger.log('Opening file for output: ' + aval, "P")
            try:
                aval = codecs.open(aval, 'w', 'utf-8')
            except Exception as e:
                print e
                sys.exit(1)
        elif atype == 'outfont':
            if tool is None:
                logger.log("Can't specify a font without a font tool", "X")
            outfont = aval
            outfontpath = apath
            outfontbase = abase
            outfontext = aext

        elif atype == 'optiondict':  # Turn multiple options in the form ['opt1=a', 'opt2=b'] into a dictionary
            avaldict={}
            if aval is not None:
                for option in aval:
                    x = option.split("=", 1)
                    if len(x) != 2:
                        logger.log("options must be of the form 'param=value'", "S")
                    if x[1] == "\\t": x[1] = "\t"  # Special handling for tab characters
                    avaldict[x[0]] = x[1]
            aval = avaldict

        setattr(args, ainfo['name'], aval)

# Open fonts - needs to be done after processing other arguments so logger and params are defined

    for name, aval in infontlist:
        if chain and name == 'ifont':
            aval = chain["font"]
        else:
            if tool == "FF" : aval = fontforge.open(aval)
            if tool == "UFO": aval = Ufont(aval, params=params)
            if tool == "FT" : aval = ttLib.TTFont(aval)
        setattr(args, name, aval)  # Assign the font object to args attribute

# All arguments processed, now call the main function
    setattr(args, "paramsobj", params)
    setattr(args, "cmdlineargs", argv)
    newfont = fn(args)
# If an output font is expected and one is returned, output the font
    if outfont and newfont is not None:
        if chain:  # return font to be handled by chain()
            return newfont
        else:
            # Backup the font if output is overwriting original input font
            if outfont == infontlist[0][1]:
                backupdir = os.path.join(outfontpath, execparams['backupdir'])
                backupmax = int(execparams['backupkeep'])
                backup = str2bool(execparams['backup'])

                if backup:
                    if not os.path.isdir(backupdir):  # Create backup directory if not present
                        try:
                            os.mkdir(backupdir)
                        except Exception as e:
                            print e
                            sys.exit(1)
                    backupbase = os.path.join(backupdir, outfontbase+outfontext)
                    # Work out backup name based on existing backups
                    nums = sorted([int(i[len(backupbase)+1-len(i):-1]) for i in glob(backupbase+".*~")])  # Extract list of backup numbers from existing backups
                    newnum = max(nums)+1 if nums else 1
                    backupname = backupbase+"."+str(newnum)+"~"
                    # Backup the font
                    newfont.logger.log("Backing up input font to "+backupname, "P")
                    shutil.copytree(outfont, backupname)
                    # Purge old backups
                    for i in range(0, len(nums) - backupmax + 1):
                        backupname = backupbase+"."+str(nums[i])+"~"
                        newfont.logger.log("Purging old backup "+backupname, "I")
                        shutil.rmtree(backupname)
                else:
                    newfont.logger.log("No font backup done due to backup parameter setting", "W")
            # Output the font
            if tool == "FF":
                if not quiet: logger.log("Saving font to " + outfont, "P")
                if outfontext.lower() == ".ufo" or outfontext.lower() == '.ttf':
                    newfont.generate(outfont)
                else: newfont.save(outfont)
            elif tool == "FT":
                if not quiet: logger.log("Saving font to " + outfont, "P")
                newfont.save(outfont)
            else:  # Must be Pyslifont Ufont
                newfont.write(outfont)

    if logfile: logfile.close()
Ejemplo n.º 3
0
def execute(tool, fn, argspec, chain = None):
    # Function to handle parameter parsing, font and file opening etc in command-line scripts
    # Supports opening (and saving) fonts using FontForge (FF), PysilFont UFO (UFO) or fontTools (FT)
    # Special handling for:
    #   -d  variation on -h to print extra info about defaults
    #   -q  quiet mode - only output a single line with count of errors (if there are any)
    #   -l  opens log file and also creates a logger function to write to the log file
    #   -p  other parameters. Includes backup settings and loglevel/scrlevel settings for logger
    #       for UFOlib scripts, also includes all outparams keys and ufometadata settings

    chainfirst = False
    if chain == "first": # If first call to execute has this set, only do the final return part of chaining
        chainfirst = True
        chain = None

    params = chain["params"] if chain else parameters()
    logger = chain["logger"] if chain else params.logger  # paramset has already created a basic logger
    argv   = chain["argv"]   if chain else sys.argv

    if tool == "FF":
        import fontforge
        if fontforge.hasUserInterface():
            return  # Execute is for command-line use
        fontforge.loadPrefs()
        fontforge.setPrefs("PreserveTables", "DSIG,Feat,Glat,Gloc,LTSH,Silf,Sill,Silt,VDMX,hdmx")  ## Perhaps should be a parameter and check for existing values
    elif tool == "UFO":
        from silfont.ufo import Ufont
    elif tool == "FT":
        from fontTools import ttLib
    elif tool == "" or tool is None:
        tool = None
    else:
        logger.log("Invalid tool in call to execute()", "X")
        return
    basemodule = sys.modules[fn.__module__]
    poptions = {}
    poptions['prog'] = splitfn(argv[0])[1]
    poptions['description'] = basemodule.__doc__
    poptions['formatter_class'] = argparse.RawDescriptionHelpFormatter
    epilog = "For more help see https://github.com/silnrsi/pysilfont/blob/master/docs/scripts.md#" + poptions['prog'] + "\n\n"
    poptions['epilog'] = epilog + "Version: " + params.sets['default']['version'] + "\n" + params.sets['default']['copyright']

    parser = argparse.ArgumentParser(**poptions)
    parser._optionals.title = "other arguments"

    # Add standard arguments
    standardargs = [
            ('-d', '--defaults', {'help': 'Display help with info on default values', 'action': 'store_true'}, {}), 
            ('-q', '--quiet', {'help': 'Quiet mode - only display errors', 'action': 'store_true'}, {}), 
            ('-l', '--log', {'help': 'Log file'}, {'type': 'outfile'}), 
            ('-p', '--params', {'help': 'Other parameters - see parameters.md for details', 'action': 'append'}, {'type': 'optiondict'})]
    standardargsindex = ['defaults', 'quiet', 'log', 'params']

    suppliedargs = []
    for a in argspec:
        argn = a[:-2][-1]  # [:-2] will give either 1 or 2, the last of which is the full argument name
        if argn[0:2] == "--": argn = argn[2:]  # Will start with -- for options
        suppliedargs.append(argn)
    for i, arg in enumerate(standardargsindex):
        if arg not in suppliedargs: argspec.append(standardargs[i])

    # Special handling for "-d" to print default value info with help text
    defhelp = False
    if "-d" in argv:
        defhelp = True
        pos = argv.index("-d")
        argv[pos] = "-h"  # Set back to -h for argparse to recognise
        deffiles = []
        defother = []

    quiet = True if "-q" in argv else False
    if quiet: logger.scrlevel = "S"

    # Process the supplied argument specs, add args to parser, store other info in arginfo
    arginfo = []
    logdef = None
    for a in argspec:
        # Process all but last tuple entry as argparse arguments
        nonkwds = a[:-2]
        kwds = a[-2]
        parser.add_argument(*nonkwds, **kwds)
        # Create dict of framework keywords using argument name
        argn = nonkwds[-1]  # Find the argument name from first 1 or 2 tuple entries
        if argn[0:2] == "--": argn = argn[2:]  # Will start with -- for options
        ainfo=a[-1]
        ainfo['name']=argn
        if argn == 'log':
            logdef = ainfo['def'] if 'def' in ainfo else None
        arginfo.append(ainfo)
        if defhelp:
            arg = nonkwds[0]
            if 'def' in ainfo:
                deffiles.append([arg, ainfo['def']])
            elif 'default' in kwds:
                defother.append([arg, kwds['default']])

    # if -d specified, change the help epilog to info about argument defaults
    if defhelp:
        if not (deffiles or defother):
            deftext = "No defaults for parameters/options"
        else:
            deftext = "Defaults for parameters/options - see user docs for details\n"
        if deffiles:
            deftext = deftext + "\n  Font/file names\n"
            for (param, defv) in deffiles:
                deftext = deftext + '    {:<20}{}\n'.format(param, defv)
        if defother:
            deftext = deftext + "\n  Other parameters\n"
            for (param, defv) in defother:
                deftext = deftext + '    {:<20}{}\n'.format(param, defv)
        parser.epilog = deftext + "\n\n" + parser.epilog

    # Parse the command-line arguments. If errors or -h used, procedure will exit here
    args = parser.parse_args(argv[1:])

    # Process the first positional parameter to get defaults for file names
    fppval = getattr(args, arginfo[0]['name'])
    if fppval is None: fppval = ""  # For scripts that can be run with no positional parameters
    (fppath, fpbase, fpext) = splitfn(fppval)  # First pos param use for defaulting

    # Process parameters
    if chain:
        execparams = params.sets["main"]
        args.params = {}  # clparams not used when chaining
    else:
        # Read config file from disk if it exists
        configname = os.path.join(fppath, "pysilfont.cfg")
        if os.path.exists(configname):
            params.addset("config file", configname, configfile=configname)
        else:
            params.addset("config file")  # Create empty set
        if not quiet and "scrlevel" in params.sets["config file"]: logger.scrlevel = params.sets["config file"]["scrlevel"]

        # Process command-line parameters
        clparams = {}
        if 'params' in args.__dict__:
            if args.params is not None:
                for param in args.params:
                    x = param.split("=", 1)
                    if len(x) != 2:
                        logger.log("params must be of the form 'param=value'", "S")
                    if x[1] == "\\t": x[1] = "\t"  # Special handling for tab characters
                    clparams[x[0]] = x[1]

        args.params = clparams
        params.addset("command line", "command line", inputdict=clparams)
        if not quiet and "scrlevel" in params.sets["command line"]: logger.scrlevel = params.sets["command line"]["scrlevel"]

        # Create main set of parameters based on defaults then update with config file values and command line values
        params.addset("main", copyset="default")
        params.sets["main"].updatewith("config file")
        params.sets["main"].updatewith("command line")
        execparams = params.sets["main"]

    # Set up logging
    if chain:
        setattr(args, 'logger', logger)
        args.logfile = logger.logfile
    else:
        logfile = None
        logname = args.log if 'log' in args.__dict__ and args.log is not None else ""
        if 'log' in args.__dict__:
            if logdef is not None:
                (path, base, ext) = splitfn(logname)
                (dpath, dbase, dext) = splitfn(logdef)
                if not path:
                    if base and ext:  # If both specified then use cwd, ie no path
                        path = ""
                    else:
                        path = (fppath if dpath is "" else os.path.join(fppath, dpath))
                if not base:
                    if dbase == "":
                        base = fpbase
                    elif dbase[0] == "_":  # Append to font name if starts with _
                        base = fpbase + dbase
                    else:
                        base = dbase
                if not ext and dext: ext = dext
                logname = os.path.join(path, base+ext)
            if logname == "":
                logfile = None
            else:
                (logname, logpath, exists) = fullpath(logname)
                if not exists:
                    logger.log("Log file directory " + logpath + " does not exist", "S")
                logger.log('Opening log file for output: ' + logname, "P")
                try:
                    logfile = io.open(logname, "w", encoding="utf-8")
                except Exception as e:
                    print(e)
                    sys.exit(1)
                args.log = logfile
        # Set up logger details
        logger.loglevel = execparams['loglevel'].upper()
        if not quiet: logger.scrlevel = execparams['scrlevel'].upper()
        logger.logfile = logfile
        setattr(args, 'logger', logger)

# Process the argument values returned from argparse

    outfont = None
    infontlist = []
    for c, ainfo in enumerate(arginfo):
        aval = getattr(args, ainfo['name'])
        if ainfo['name'] in ('params', 'log'): continue  # params and log already processed
        atype = None
        adef = None
        if 'type' in ainfo:
            atype = ainfo['type']
            if atype not in ('infont', 'outfont', 'infile', 'outfile', 'incsv', 'filename', 'optiondict'):
                logger.log("Invalid type of " + atype + " supplied in argspec", "X")
            if atype != 'optiondict':  # All other types are file types, so adef must be set, even if just to ""
                adef = ainfo['def'] if 'def' in ainfo else ""
            if adef is None and aval is None:  # If def explicitly set to None then this is optional
                setattr(args, ainfo['name'], None)
                continue

        if c == 0:
            if aval is None : logger.log("Invalid first positional parameter spec", "X")
            if aval[-1] in ("\\","/"): aval = aval[0:-1]  # Remove trailing slashes
        else:  #Handle defaults for all but first positional parameter
            if adef is not None:
                if not aval: aval = ""
                if aval == "" and adef == "":  # Only valid for output font parameter
                    if atype != "outfont":
                        logger.log("No value suppiled for " + ainfo['name'], "S")
                        ## Not sure why this needs to fail - we need to cope with other optional file or filename parameters
                (apath, abase, aext) = splitfn(aval)
                (dpath, dbase, dext) = splitfn(adef)  # dpath should be None
                if not apath:
                    if abase and aext:  # If both specified then use cwd, ie no path
                        apath = ""
                    else:
                        apath = fppath
                if not abase:
                    if dbase == "":
                        abase = fpbase
                    elif dbase[0] == "_":  # Append to font name if starts with _
                        abase = fpbase + dbase
                    else:
                        abase = dbase
                if not aext:
                    if dext:
                        aext = dext
                    elif (atype == 'outfont' or atype == 'infont'): aext = fpext
                aval = os.path.join(apath, abase+aext)

        # Open files/fonts
        if atype == 'infont':
            if tool is None:
                logger.log("Can't specify a font without a font tool", "X")
            infontlist.append((ainfo['name'], aval))  # Build list of fonts to open when other args processed
        elif atype == 'infile':
            logger.log('Opening file for input: '+aval, "P")
            try:
                aval = io.open(aval, "r", encoding="utf-8")
            except Exception as e:
                print(e)
                sys.exit(1)
        elif atype == 'incsv':
            logger.log('Opening file for input: '+aval, "P")
            aval = csvreader(aval)
        elif atype == 'outfile':
            (aval, path, exists) = fullpath(aval)
            if not exists:
                logger.log("Output file directory " + path + " does not exist", "S")
            logger.log('Opening file for output: ' + aval, "P")
            try:
                aval = io.open(aval, 'w', encoding="utf-8")
            except Exception as e:
                print(e)
                sys.exit(1)
        elif atype == 'outfont':
            if tool is None:
                logger.log("Can't specify a font without a font tool", "X")
            outfont = aval
            outfontpath = apath
            outfontbase = abase
            outfontext = aext

        elif atype == 'optiondict':  # Turn multiple options in the form ['opt1=a', 'opt2=b'] into a dictionary
            avaldict={}
            if aval is not None:
                for option in aval:
                    x = option.split("=", 1)
                    if len(x) != 2:
                        logger.log("options must be of the form 'param=value'", "S")
                    if x[1] == "\\t": x[1] = "\t"  # Special handling for tab characters
                    avaldict[x[0]] = x[1]
            aval = avaldict

        setattr(args, ainfo['name'], aval)

# Open fonts - needs to be done after processing other arguments so logger and params are defined

    for name, aval in infontlist:
        if chain and name == 'ifont':
            aval = chain["font"]
        else:
            if tool == "FF" : aval = fontforge.open(aval)
            if tool == "UFO": aval = Ufont(aval, params=params)
            if tool == "FT" : aval = ttLib.TTFont(aval)
        setattr(args, name, aval)  # Assign the font object to args attribute

# All arguments processed, now call the main function
    setattr(args, "paramsobj", params)
    setattr(args, "cmdlineargs", argv)
    newfont = fn(args)
# If an output font is expected and one is returned, output the font
    if chainfirst: chain = True # Special handling for first call of chaining
    if newfont:
        if chain:  # return font to be handled by chain()
            return (args, newfont)
        else:
            if outfont:
                # Backup the font if output is overwriting original input font
                if outfont == infontlist[0][1]:
                    backupdir = os.path.join(outfontpath, execparams['backupdir'])
                    backupmax = int(execparams['backupkeep'])
                    backup = str2bool(execparams['backup'])

                    if backup:
                        if not os.path.isdir(backupdir):  # Create backup directory if not present
                            try:
                                os.mkdir(backupdir)
                            except Exception as e:
                                print(e)
                                sys.exit(1)
                        backupbase = os.path.join(backupdir, outfontbase+outfontext)
                        # Work out backup name based on existing backups
                        nums = sorted([int(i[len(backupbase)+1-len(i):-1]) for i in glob(backupbase+".*~")])  # Extract list of backup numbers from existing backups
                        newnum = max(nums)+1 if nums else 1
                        backupname = backupbase+"."+str(newnum)+"~"
                        # Backup the font
                        newfont.logger.log("Backing up input font to "+backupname, "P")
                        shutil.copytree(outfont, backupname)
                        # Purge old backups
                        for i in range(0, len(nums) - backupmax + 1):
                            backupname = backupbase+"."+str(nums[i])+"~"
                            newfont.logger.log("Purging old backup "+backupname, "I")
                            shutil.rmtree(backupname)
                    else:
                        newfont.logger.log("No font backup done due to backup parameter setting", "W")
                # Output the font
                if tool == "FF":
                    logger.log("Saving font to " + outfont, "P")
                    if outfontext.lower() == ".ufo" or outfontext.lower() == '.ttf':
                        newfont.generate(outfont)
                    else: newfont.save(outfont)
                elif tool == "FT":
                    logger.log("Saving font to " + outfont, "P")
                    newfont.save(outfont)
                else:  # Must be Pyslifont Ufont
                    newfont.write(outfont)
            else:
                logger.log("Font returned to execute() but no output font is specified in arg spec", "X")
    elif chain:             # ) When chaining return just args - the font can be accessed by args.ifont
        return (args, None) # ) assuming that the script has not changed the input font

    if logger.errorcount or logger.warningcount:
        message = "Command completed with " + str(logger.errorcount) + " errors and " + str(logger.warningcount) + " warnings"
        if logger.scrlevel in ("S", "E") and logname is not "":
            if logger.scrlevel == "S" or logger.warningcount: message = message + " - see " + logname
        if logger.errorcount:
            if quiet: logger.raisescrlevel("E")
            logger.log(message, "E")
            logger.resetscrlevel()
        else:
            logger.log(message, "P")
        if logger.scrlevel == "P" and logger.warningcount: logger.log("See log file for warning messages or rerun with '-p scrlevel=w'", "P")
    else:
        logger.log("Command completed with no warnings", "P")

    return (args, newfont)
Ejemplo n.º 4
0
def execute(tool, fn, argspec) :
    # Function to handle parameter parsing, font and file opening etc in command-line scripts
    # Supports opening (and saving) fonts using FontForge (FF) or PysilFont UFOlib (PSFU)
    # Special handling for:
    #   -d        variation on -h to print extra info about defaults
    #   -q  quiet mode - suppresses progress messages and sets screen logging to errors only
    #   -l  opens log file and also creates a logger function to write to the log file
    #   -p  includes loglevel and scrlevel settings for logger
    #       for UFOlib scripts, also includes all font.outparams keys except for attribOrder
    #   -v  for UFOlib scripts this sets font.outparams(UFOversion)

    logger = loggerobj() # Basic screen logger at this stage
    ff = False
    psfu = False
    if tool == "FF" :
        ff=True
        import fontforge
        if fontforge.hasUserInterface() :
            return # Execute is for command-line use
        fontforge.loadPrefs()
    elif tool == "PSFU" :
        psfu = True
        from UFOlib import Ufont
    elif tool == "" or tool is None :
        tool = None
    else :
        logger.log( "Invalid tool in call to execute()", "X")
        return
    basemodule = sys.modules[fn.__module__]
    poptions = {}
    poptions['prog'] = _splitfn(sys.argv[0])[1]
    poptions['description'] = basemodule.__doc__
    poptions['formatter_class'] = argparse.RawDescriptionHelpFormatter
    if hasattr(basemodule, '__version__') : poptions['epilog'] = "Version: " + basemodule.__version__

    parser = argparse.ArgumentParser(**poptions)

    # Add standard arguments
    standardargs = [
            ('-d','--defaults', {'help': 'Display help with info on default values', 'action': 'store_true'}, {}),
            ('-q','--quiet',{'help': 'Quiet mode - only display errors', 'action': 'store_true'}, {})]
    standardargsindex = ['defaults','quiet']
    if psfu:
        standardargs.extend([
            ('-v','--version',{'help': 'UFO version to output'},{}),
            ('-p','--params',{'help': 'Other font parameters','action': 'append'}, {'type': 'optiondict'})])
        standardargsindex.extend(['version','params'])

    suppliedargs = []
    for a in argspec :
        argn = a[:-2][-1] # [:-2] will give either 1 or 2, the last of which is the full argument name
        if argn[0:2] == "--" : argn = argn[2:] # Will start with -- for options
        suppliedargs.append(argn)

    for i,arg in enumerate(standardargsindex) :
        if arg not in suppliedargs: argspec.append(standardargs[i])

    # Special handling for "-d" to print default value info with help text
    defhelp = False
    if "-d" in sys.argv:
        defhelp = True
        pos = sys.argv.index("-d")
        sys.argv[pos] = "-h" # Set back to -h for argparse to recognise
        deffiles=[]
        defother=[]

    quiet = True if "-q" in sys.argv else False

    # Process the supplied argument specs, add args to parser, store other info in arginfo
    arginfo = []
    logdef = None
    for a in argspec :
        # Process all but last tuple entry as argparse arguments
        nonkwds = a[:-2]
        kwds = a[-2]
        parser.add_argument(*nonkwds, **kwds)
        # Create dict of framework keywords using argument name
        argn = nonkwds[-1] # Find the argument name from first 1 or 2 tuple entries
        if argn[0:2] == "--" : argn = argn[2:] # Will start with -- for options
        ainfo=a[-1]
        ainfo['name']=argn
        if argn == 'log' :
            logdef = ainfo['def'] if 'def' in ainfo else None
        arginfo.append(ainfo)
        if defhelp:
            arg = nonkwds[0]
            if 'def' in ainfo:
                deffiles.append([arg,ainfo['def']])
            elif 'default' in kwds:
                defother.append([arg,kwds['default']])

    # if -d specified, change the help epilog to info about argument defaults
    if defhelp:
        if not (deffiles or defother):
            deftext = "No defaults for parameters/options"
        else:
            deftext = "Defaults for parameters/options - see user docs for details\n"
        if deffiles:
            deftext = deftext + "\n  Font/file names\n"
            for (param,defv) in deffiles:
                deftext = deftext + '    {:<20}{}\n'.format(param,defv)
        if defother:
            deftext = deftext + "\n  Other parameters\n"
            for (param,defv) in defother:
                deftext = deftext + '    {:<20}{}\n'.format(param,defv)
        parser.epilog = deftext

    # Parse the command-line arguments. If errors or -h used, procedure will exit here
    args = parser.parse_args()

    # Process the first positional parameter to get defaults for file names
    fppval = getattr(args,arginfo[0]['name'])
    if fppval is None : fppval = "" # For scripts that can be run with no positional parameters
    (fppath,fpbase,fpext)=_splitfn(fppval) # First pos param use for defaulting

    # Process command-line parameters and config file
    clparams = {}
    if 'params' in args.__dict__ :
        if args.params is not None :
            for param in args.params :
                x = param.split("=",1)
                if len(x) <> 2 :
                    logger.log( "params must be of the form 'param=value'", "S")
                if x[1] == "\\t" : x[1] = "\t" # Special handling for tab characters
                clparams[x[0]] = x[1]

    if psfu and 'version' in args.__dict__:
        if args.version : clparams["UFOversion"] = args.version

    args.params = clparams

    # Read config file from disk if it exists
    cfgparams = {}
    configname = os.path.join(fppath, "pysilfont.cfg")
    if os.path.exists(configname) :
        config = csvreader(configname, logger = logger, numfields = 2)
        for param,value in config : cfgparams[param] = value

    # Create list of parameters for use with logging and backup from base parameters overdidden by any congif file or command line parameters
    lbparams={}
    for param in baseparamsindex :
        lbparams[param] = cfgparams[param] if param in cfgparams else baseparamsindex[param]['value']
        if param in clparams : lbparams[param] = clparams[param]

    # Set up logging
    logfile = None
    if 'log' in args.__dict__ :
        logname = args.log if args.log else ""
        if logdef is not None :
            (path,base,ext)=_splitfn(logname)
            (dpath,dbase,dext)=_splitfn(logdef) # dpath should be None
            if not path :
                if base and ext : # If both specified then use cwd, ie no path
                    path = ""
                else:
                    path=fppath
            if not base :
                if dbase == "" :
                    base = fpbase
                elif dbase[0] == "_" : # Append to font name if starts with _
                    base = fpbase + dbase
                else:
                    base = dbase
            if not ext and dext : ext = dext
            logname = os.path.join(path,base+ext)
        if not quiet : logger.log( 'Opening log file for output: '+logname, "P")
        try :
            logfile=open(logname,"w")
        except Exception as e :
            print e
            sys.exit(1)
        args.log = logfile
    # Set up logger details
    logger.loglevel = lbparams['loglevel'].upper()
    logger.scrlevel = "E" if quiet else lbparams['scrlevel'].upper()
    logger.logfile = logfile
    setattr(args,'logger',logger)

# Process the argument values returned from argparse

    outfont = None
    infontlist = []
    for c,ainfo in enumerate(arginfo) :
        aval = getattr(args,ainfo['name'])
        if ainfo['name'] in  ('params', 'log') : continue # params and log already processed
        atype = None
        adef = None
        if 'type' in ainfo :
            atype = ainfo['type']
            if atype <> 'optiondict' : # All other types are file types, so adef must be set, even if just to ""
                adef = ainfo['def'] if 'def' in ainfo else ""

        if c == 0 :
            if aval[-1] in ("\\","/") : aval = aval[0:-1] # Remove trailing slashes
        else : #Handle defaults for all but first positional parameter
            if adef is not None:
                if not aval : aval=""
                if aval == "" and adef == "" : # Only valid for output font parameter
                    if atype <> "outfont" :
                        logger.log( "No value suppiled for " + ainfo['name'], "S")
                        sysexit()
                (apath,abase,aext)=_splitfn(aval)
                (dpath,dbase,dext)=_splitfn(adef) # dpath should be None
                if not apath :
                    if abase and aext : # If both specified then use cwd, ie no path
                        apath = ""
                    else:
                        apath=fppath
                if not abase :
                    if dbase == "" :
                        abase = fpbase
                    elif dbase[0] == "_" : # Append to font name if starts with _
                        abase = fpbase + dbase
                    else:
                        abase = dbase
                if not aext :
                    if dext :
                        aext = dext
                    elif (atype=='outfont' or atype=='infont') : aext = fpext
                aval = os.path.join(apath,abase+aext)


        # Open files/fonts
        if atype=='infont' :
            if tool is None:
                logger.log( "Can't specify a font without a font tool", "X")
            infontlist.append((ainfo['name'],aval)) # Build list of fonts to open when other args processed
        elif atype=='infile' :
            if not quiet : logger.log( 'Opening file for input: '+aval, "P")
            try :
                aval=open(aval,"r")
            except Exception as e :
                print e
                sys.exit(1)
        elif atype=='incsv' :
            if not quiet : logger.log( 'Opening file for input: '+aval, "P")
            aval = csvreader(aval)
        elif atype=='outfile':
            if not quiet : logger.log( 'Opening file for output: '+aval, "P")
            try :
                aval=open(aval,"w")
            except Exception as e :
                print e
                sys.exit(1)
        elif atype=='outfont' :
            if tool is None:
                logger.log("Can't specify a font without a font tool", "X")
            outfont = aval
            outfontpath = apath
            outfontbase = abase
            outfontext = aext

        elif atype=='optiondict' : # Turn multiple options in the form ['opt1=a','opt2=b'] into a dictionary
            avaldict={}
            if aval is not None:
                for option in aval:
                    x = option.split("=",1)
                    if len(x) <> 2 :
                        logger.log( "params must be of the form 'param=value'", "S")
                    if x[1] == "\\t" : x[1] = "\t" # Special handling for tab characters
                    avaldict[x[0]] = x[1]
            aval = avaldict

        setattr(args,ainfo['name'],aval)

# Open fonts - needs to be done after processing other arguments so logger and params are defined

    for name,aval in infontlist :
        if ff : aval=fontforge.open(aval)
        if psfu: aval=Ufont(aval, logger = logger, cfgparams=cfgparams, clparams=clparams)
        setattr(args,name,aval) # Assign the font object to args attribute

# All arguments processed, now call the main function
    newfont = fn(args)
# If an output font is expected and one is returned, output the font
    if outfont and newfont is not None:
        # Backup the font if output is overwriting original input font
        if outfont == infontlist[0][1] :
            backupdir = os.path.join(outfontpath,lbparams['backupdir'])
            backupmax = int(lbparams['backupkeep'])
            backup = str2bool(lbparams['backup'])

            if backup :
                if not os.path.isdir(backupdir) : # Create backup directory if not present
                    try:
                        os.mkdir(backupdir)
                    except Exception as e :
                        print e
                        sys.exit(1)
                backupbase = os.path.join(backupdir,outfontbase+outfontext)
                # Work out backup name based on existing backups
                nums = sorted([ int(i[len(backupbase)+1-len(i):-1]) for i in glob(backupbase+".*~")]) # Extract list of backup numbers from existing backups
                newnum = max(nums)+1 if nums else 1
                backupname = backupbase+"."+str(newnum)+"~"
                # Backup the font
                newfont.logger.log("Backing up input font to "+backupname,"P")
                shutil.copytree(outfont,backupname)
                # Purge old backups
                for i in range(0, len(nums) - backupmax + 1) :
                    backupname = backupbase+"."+str(nums[i])+"~"
                    newfont.logger.log("Purging old backup "+backupname,"I")
                    shutil.rmtree(backupname)
            else:
                newfont.logger.log("No font backup done due to backup parameter setting","W")
        # Output the font
        if ff:
            if not quiet : logger.log( "Saving font to " + outfont, "P")
            if outfontext.lower() == ".ufo" or outfontext.lower() == '.ttf':
                newfont.generate(outfont)
            else : newfont.save(outfont)
        else: # Must be Pyslifont Ufont
            newfont.write(outfont)

    if logfile : logfile.close()
Ejemplo n.º 5
0
#!/home/rakesh/pdf2htmlEX/fontforge-pdf2htmlEX/fontforgeexe/fontforge
#Needs: fonts/Ambrosia.sfd

#Test the fontforge module (but not its types)
import os, fontforge;

foo = fontforge.getPrefs("DetectDiagonalStems")
fontforge.setPrefs("DetectDiagonalStems",~foo)
fontforge.loadPrefs();
# fontforge.savePrefs()
fontforge.defaultOtherSubrs();
# fontforge.readOtherSubrsFile();

foo = fontforge.hasSpiro()

# fontforge.loadEncodingFile()
# fontforge.loadNamelist()
# fontforge.loadNamelistDir()
# fontforge.loadPlugin()
# fontforge.loadPluginDir()
# fontforge.preloadCidmap()

fontforge.printSetup("lpr")

if ( (fontforge.unicodeFromName("A")!=65) | (fontforge.unicodeFromName("uni030D")!=0x30D) ) :
  raise ValueError, "Wrong return from unicodeFromName"

foo = fontforge.version()

ambrosia = os.path.join("/home/rakesh/pdf2htmlEX/fontforge-pdf2htmlEX/tests", "fonts", "Ambrosia.sfd")
Ejemplo n.º 6
0
 def __init__(self):
     fontforge.loadPrefs()
     pth = os.path.expanduser('~/Library/Fonts/')
     self.font=fontforge.open(pth+'aaux_pro_bd_it_osf.ttf')
     self.layers = defaultdict(list)
Ejemplo n.º 7
0
#!/usr/local/bin/fontforge
#Needs: fonts/Ambrosia.sfd

#Test the fontforge module (but not its types)
import fontforge;

foo = fontforge.getPrefs("DetectDiagonalStems")
fontforge.setPrefs("DetectDiagonalStems",~foo)
fontforge.loadPrefs();
# fontforge.savePrefs() 
fontforge.defaultOtherSubrs();
# fontforge.readOtherSubrsFile(); 

foo = fontforge.hasSpiro()

# fontforge.loadEncodingFile() 
# fontforge.loadNamelist() 
# fontforge.loadNamelistDir() 
# fontforge.loadPlugin() 
# fontforge.loadPluginDir() 
# fontforge.preloadCidmap() 

fontforge.printSetup("lpr")

if ( (fontforge.unicodeFromName("A")!=65) | (fontforge.unicodeFromName("uni030D")!=0x30D) ) :
  raise ValueError, "Wrong return from unicodeFromName"

foo = fontforge.version()

fonts = fontforge.fonts()
if ( len(fonts)!=0 ) :