Example #1
0
def CurrentFont():
    if fontforge.hasUserInterface():
        _font = fontforge.activeFontInUI()
        return RFont(_font)
    if __DEBUG__:
        print "CurrentFont(): fontforge not running with user interface,"
    return None
Example #2
0
def CurrentFont():
    if fontforge.hasUserInterface():
        _font = fontforge.activeFontInUI()
        return RFont(_font)
    if __DEBUG__:
        print "CurrentFont(): fontforge not running with user interface,"
    return None
Example #3
0
    def dumpFontForgeAPI(testFontPath, printModule=False,
            printFont=False, printGlyph=False,
            printLayer=False, printContour=False, printPoint=False):
        def printAPI(item, name):
            print 
            print "-"*80
            print "API of", item
            names = dir(item)
            names.sort()
            print

            if printAPI:
                for n in names:
                    print
                    print "%s.%s"%(name, n)
                    try:
                        print getattr(item, n).__doc__
                    except:
                        print "# error showing", n
        # module
        if printModule:
            print "module file:", fontforge.__file__
            print "version:", fontforge.version()
            print "module doc:", fontforge.__doc__
            print "has User Interface:", fontforge.hasUserInterface()
            print "has Spiro:", fontforge.hasSpiro()
            printAPI(fontforge, "fontforge")
        
        # font
        fontObj = fontforge.open(testFontPath)
        if printFont:
            printAPI(fontObj, "font")
    
        # glyph
        glyphObj = fontObj["A"]
        if printGlyph:
                printAPI(glyphObj, "glyph")
        
        # layer
        layerObj = glyphObj.foreground
        if printLayer:
            printAPI(layerObj, "layer")

        # contour
        contourObj = layerObj[0]
        if printContour:
            printAPI(contourObj, "contour")
        
        # point
        if printPoint:
            pointObj = contourObj[0]
            printAPI(pointObj, "point")
        
        
        # other objects
        penObj = glyphObj.glyphPen()
        printAPI(penObj, "glyphPen")
Example #4
0
        outname = conf.get('main', 'ap')
        if os.path.exists(outname) : readAP(font, outname)
        mergeAPInfo(font)
        myFfFont = FfFont(font)
        buildGraphite(conf, None, myFfFont, outputfont)
    else :
        buildGraphite(conf, None, None, outputfont)
    writecfg(conf, cfg)
    os.chdir(cwd)

def loadFont(font) :
    if getcfg(font) :
        if 'initScriptString' not in font.persistent : font.persistent['initScriptString'] = None
        if not font.temporary : font.temporary = {}
        font.temporary['generateFontPostHook'] = doGenerate

if fontforge.hasUserInterface() :
    fontforge.hooks['loadFontHook'] = loadFont
    fontforge.registerMenuItem(loadConfig, None, None, "Font", None, "Graide", "Load configuration")
    fontforge.registerMenuItem(editConfig, None, None, "Font", None, "Graide", "Edit configuration")
else:
    f = fontforge.open(os.path.abspath(sys.argv[1]))
    cfg = getcfg(f)
    if not cfg :
        print "No configuration, can't build"
        sys.exit(1)
    conf = RawConfigParser()
    conf.read(cfg)
    f.generate(conf.get('main', 'font'), flags = ('opentype',))
    sys.exit(0)
Example #5
0
	f['v'].right_side_bearing = diferencia

    if 'w' in f:
	f['w'].left_side_bearing = diferencia
	f['w'].right_side_bearing = diferencia

    if 'y' in f:
	f['y'].left_side_bearing = diferencia
	f['y'].right_side_bearing = diferencia

    if 'x' in f:
	f['x'].left_side_bearing = 0
	f['x'].right_side_bearing = 0
	diferencia = int( ( (nWidth * xProportion ) * params['xBoth'] / 100 ) - f['x'].width ) / 2
	f['x'].left_side_bearing = diferencia
	f['x'].right_side_bearing = diferencia

    if 'z' in f:
	f['z'].left_side_bearing = 0
	f['z'].right_side_bearing = 0
	diferencia = int( ( (nWidth * zProportion ) * params['zBoth'] / 100 ) - f['z'].width ) / 2
	f['z'].left_side_bearing = diferencia
	f['z'].right_side_bearing = diferencia

    print "done";

if fontforge.hasUserInterface():
    keyShortcut = None
    menuText = "Spacing macro"
    fontforge.registerMenuItem(spacing, None, None, "Font", keyShortcut, menuText)
Example #6
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()
Example #7
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).
    ff = False
    psfu = False
    if tool == "FF" :
        ff=True
        import fontforge
        if fontforge.hasUserInterface() :
            return # Execute is for command-line use
    elif tool == "PSFU" :
        psfu = True
        from UFOlib import Ufont
    elif tool == "" or tool is None :
        tool = None
    else :
        print "Invalid tool in call to execute()"
        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)
    
    # 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=[]
    if "-h" in sys.argv or "--help" in sys.argv: # Add extra argument to display in help text
        argspec.insert(0,('-d',{'help': 'Display help with info on default values', 'action': 'store_true'}, {}))

# Process the supplied argument specs, add args to parser, store other info in arginfo
    arginfo = []
    for c,a in enumerate(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
        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\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 argument values returned from argparse
    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
    outfont = None
    
    for c,ainfo in enumerate(arginfo) :
        aval = getattr(args,ainfo['name'])
        atype = ainfo['type'] if 'type' in ainfo else None
        adef = ainfo['def'] if 'def' in ainfo else None
        if c <> 0 : #Handle defaults for all but first positional parameter
            if adef :
                if not aval : aval=""               
                (apath,abase,aext)=_splitfn(aval)
                (dpath,dbase,dext)=_splitfn(adef) # dpath should be None
                if not apath : apath=fppath
                if not abase : abase = fpbase + 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:
                print "Can't specify a font without a font tool"
                sys.exit()
            print 'Opening font: ',aval
            try :
                if ff : aval=fontforge.open(aval)
                if psfu: aval=Ufont(aval)
            except Exception as e :
                print e
                sys.exit()
        elif atype=='infile' :
            print 'Opening file for input: ',aval
            try :
                aval=open(aval,"r")
            except Exception as e :
                print e
                sys.exit()
        elif atype=='outfile' :
            print 'Opening file for output: ',aval
            try :
                aval=open(aval,"w")
            except Exception as e :
                print e
                sys.exit()
        elif atype=='outfont' :
            if tool is None:
                print "Can't specify a font without a font tool"
                sys.exit() 
            outfont=aval # Can only be one outfont
            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)
                    avaldict[x[0]] = x[1]
            aval = avaldict
        
        setattr(args,ainfo['name'],aval)

# All arguments processed, now call the main function
    result = fn(args)
    if outfont and result is not None:
        print "Saving font to " + outfont
        if ff:
            if outfontext=="ufo":
                result.generate(outfont)
            else : result.save(outfont)
        else: # Must be Pyslifont Ufont
            result.write(outfont)
Example #8
0
def execute(tool, fn, argspec) :
    ff = False
    rfb = False
    if tool == "FF" :
        ff=True
        import fontforge
        if fontforge.hasUserInterface() :
            return # Exceute is for command-line use
    elif tool == "RFB" :
        rfb = True
        from robofab.world import *
    else : return # Invalid tool     
    
    basemodule = sys.modules[fn.__module__]
    poptions = {}
    poptions['description'] = basemodule.__doc__
    if hasattr(basemodule, '__version__') : poptions['epilog'] = "Version: " + basemodule.__version__

    parser = argparse.ArgumentParser(**poptions)

# Process the supplied argument specs, add args to parser, store other info in arginfo
    arginfo = []
    for c,a in enumerate(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=fkwds=a[-1]
        ainfo['name']=argn
        arginfo.append(ainfo)

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

# Process the argument values returned from argparse
    (fppath,fpbase,fpext)=_splitfn(getattr(args,arginfo[0]['name'])) # First pos param use for defaulting
    outfont = None
    
    for c,ainfo in enumerate(arginfo) :
        aval = getattr(args,ainfo['name'])
        atype = ainfo['type'] if 'type' in ainfo else None
        adef = ainfo['def'] if 'def' in ainfo else None
        if c <> 0 : #Handle defaults for all but first positional parameter
            if adef :
                if not aval : aval=""               
                (apath,abase,aext)=_splitfn(aval)
                (dpath,dbase,dext)=_splitfn(adef) # dbase should be None
                if not apath : apath=fppath
                if not abase : abase = fpbase + 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' :
            print 'Opening font: ',aval
            try :
                if ff : aval=fontforge.open(aval)
                if rfb: aval=OpenFont(aval)
            except Exception as e :
                print e
                sys.exit()
        elif atype=='infile' :
            print 'Opening file for input: ',aval
            try :
                aval=open(aval,"r")
            except Exception as e :
                print e
                sys.exit()
        elif atype=='outfile' :
            print 'Opening file for output: ',aval
            try :
                aval=open(aval,"w")
            except Exception as e :
                print e
                sys.exit()
        elif atype=='outfont' : 
            outfont=aval # Can only be one outfont
            outfontext=aext
        
        setattr(args,ainfo['name'],aval)

# All arguments processed, now call the main function
    result = fn(args)
    if outfont :
        if result is None :
            print "No font output"
        else :
            print "Saving font to " + outfont
            if outfontext=="ufo" and ff:
                result.generate(outfont)
            else : result.save(outfont)
Example #9
0
            if len(g.references) != 0:
                g.references = follow_references(g)

        f.generate(temp_ttf.name, flags = flags)
        print('Compiling Graphite: ' + gdl_file + ' ' + temp_ttf.name + ' -> ' + ttf_file)
        compile_graphite(gdl_file, temp_ttf.name, ttf_file)
        temp_ttf.close()
    else:
        print('Generating ' + ttf_file)
        f.generate(ttf_file, flags = flags)

    print('Validating ' + ttf_file)
    subprocess.call(['fontlint', ttf_file])
    

#--------------------------------------------------------------------------

# If someone runs some script by using "fontforge -script", then name
# may be "__main__" and fontforge won't have a user interface, but
# also the |sys| module will not yet have an |argv| attribute. Weed
# out that case.  Perhaps fontforge should handle the situation
# better. (5 Nov 2009)
if __name__ == '__main__' and not fontforge.hasUserInterface() and hasattr(sys, 'argv'):

    for font_file in sys.argv[1:]:
        f = fontforge.open(font_file)
        generate_tt_font(f, name_modifier)
        f.close()

#--------------------------------------------------------------------------
Example #10
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)
Example #11
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()
Example #12
0
    def dumpFontForgeAPI(testFontPath,
                         printModule=False,
                         printFont=False,
                         printGlyph=False,
                         printLayer=False,
                         printContour=False,
                         printPoint=False):
        def printAPI(item, name):
            print
            print "-" * 80
            print "API of", item
            names = dir(item)
            names.sort()
            print

            if printAPI:
                for n in names:
                    print
                    print "%s.%s" % (name, n)
                    try:
                        print getattr(item, n).__doc__
                    except:
                        print "# error showing", n

        # module
        if printModule:
            print "module file:", fontforge.__file__
            print "version:", fontforge.version()
            print "module doc:", fontforge.__doc__
            print "has User Interface:", fontforge.hasUserInterface()
            print "has Spiro:", fontforge.hasSpiro()
            printAPI(fontforge, "fontforge")

        # font
        fontObj = fontforge.open(testFontPath)
        if printFont:
            printAPI(fontObj, "font")

        # glyph
        glyphObj = fontObj["A"]
        if printGlyph:
            printAPI(glyphObj, "glyph")

        # layer
        layerObj = glyphObj.foreground
        if printLayer:
            printAPI(layerObj, "layer")

        # contour
        contourObj = layerObj[0]
        if printContour:
            printAPI(contourObj, "contour")

        # point
        if printPoint:
            pointObj = contourObj[0]
            printAPI(pointObj, "point")

        # other objects
        penObj = glyphObj.glyphPen()
        printAPI(penObj, "glyphPen")
Example #13
0
def execute(fn, argspec):

    if fontforge.hasUserInterface():
        return  # Exceute is for command-line use

    basemodule = sys.modules[fn.__module__]
    poptions = {}
    poptions['description'] = basemodule.__doc__
    if hasattr(basemodule, '__version__'):
        poptions['epilog'] = "Version: " + basemodule.__version__

    parser = argparse.ArgumentParser(**poptions)

    # Process the supplied argument specs, add args to parser, store other info in arginfo
    arginfo = []
    for c, a in enumerate(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 = fkwds = a[-1]
        ainfo['name'] = argn
        arginfo.append(ainfo)

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

    # Process the argument values returned from argparse
    (fppath, fpbase, fpext) = _splitfn(getattr(
        args, arginfo[0]['name']))  # First pos param use for defaulting
    outfont = None

    for c, ainfo in enumerate(arginfo):
        aval = getattr(args, ainfo['name'])
        atype = ainfo['type'] if 'type' in ainfo else None
        adef = ainfo['def'] if 'def' in ainfo else None
        if c <> 0:  #Handle defaults for all but first positional parameter
            if adef:
                if not aval: aval = ""
                (apath, abase, aext) = _splitfn(aval)
                (dpath, dbase, dext) = _splitfn(adef)  # dbase should be None
                if not apath: apath = fppath
                if not abase: abase = fpbase + dbase
                if not aext:
                    if dext:
                        aext = dext
                    elif atype == 'outfont':
                        aext = fpext
                aval = os.path.join(apath, abase + aext)
        # Open files/fonts
        if atype == 'infont':
            print 'Opening font: ', aval
            try:
                aval = fontforge.open(aval)
            except Exception as e:
                print e
                sys.exit()
        elif atype == 'infile':
            print 'Opening file for input: ', aval
            try:
                aval = open(aval, "r")
            except Exception as e:
                print e
                sys.exit()
        elif atype == 'outfile':
            print 'Opening file for output: ', aval
            try:
                aval = open(aval, "w")
            except Exception as e:
                print e
                sys.exit()
        elif atype == 'outfont':
            outfont = aval  # Can only be one outfont

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


# All arguments processed, now call the main function
    result = fn(args)
    if outfont:
        print "Saving font to " + outfont
        result.save(outfont)