суббота, 28 мая 2011 г.

Calling Gimp via shell

This Python class is a wrapper for Gimp and use shell to communicate. It's part of the "HMI pybase" project, see on Project's page. It supports batch mode, rc file (config), session cleaning. Example of usage:
def gen_gimprc(gfig_dir):
    """Contents of rc file: setup directory of GFig plugin files
    """
    ret = u"(gfig-path \"%s\")"%gfid_dir.replace('\\', '\\\\') # should be (gfig-path "xx\\xx")
    return ret

...

b = Gimpsh(gimp_exe_path, locals())
gimprc = gen_gimprc(gfid_dir)
b.append((u"'(sym-new \"%(fpath)s.%(fmt)s\" %(indexed)d %(width)d %(height)d)'",), gimprc=gimprc)
try:
    # call some Scheme script sym-new with pre-setup rc file
    b.execall()
except Exception, x:
    print "Error!"
Here are the code:
import tempfile
import sys
import os
from pybase import utils

class Session(list):
    """list of jobs that ran on the same Gimp instance
    """
#    def __unicode__(self):
#        s = u"%s (%s)"%(super(Session, self).__str__(), self._opts)
#        return s

    _tmpfiles = [] # paths of temp. files - STATIC!
    def __init__(self, *a):
        super(Session, self).__init__(*a)
        self._opts = []
        self._args = []

    def __del__(self):
        # remove all temporary files
        for p in Session._tmpfiles:
            try:
                os.unlink(p)
            except:
                pass

    def copy(self):
        """Independed copy"""
        items = self[:]
        cpy = Session(items)
        cpy._opts = self._opts
        cpy._args = self._args
        return cpy

    def set_opt(self, opt, value=None):
        """option opt (-x|--x), value may be used or not. In _opts will be
        '-x'|'-x xxx'|'--x'|'--x=xxx'
        """
        if value and sys.platform=="win32":
            value = utils.quote_win32(value)
        if opt.startswith("--"):
            # long option
            f = u"%s=%s"%(opt,value) if value else opt
        else:
            f = u"%s %s"%(opt,value) if value else opt
        self._opts.append(f)

    @property
    def gimprc(self):
        raise AttributeError
    @gimprc.setter
    def gimprc(self, value):
        """Exception raising is possible
        """
        if not value: return
        (fd, name) = tempfile.mkstemp(prefix="gimprc", text=True)
        Session._tmpfiles.append(name)
        with os.fdopen(fd, "w") as f:
            f.write(value.encode("utf8"))
            f.close()
            self.set_opt("-g", unicode(name))

    def set_args(self, value):
        """Exception raising is possible
        """
        if not value: return

        if sys.platform=="win32":
            value = [utils.quote_win32(v) for v in value]
        self._args = value

    @property
    def cmdline(self):
        return u"%s %s"%(u" ".join(self._opts), u" ".join(self._args))

class Gimpsh:
    """Call gimp via shell. Called command lines are appened
    by append(). It's one call or many with several instances.
    It uses jobs (runnable via -b .. mechanism), so several
    Scheme functions can be called on one Gimp instance
    """
    def __init__(self, gimp="gimp", vars=None):
        """gimp is the full path to gimp program.
        Vars is the dict of variables for formatting, can be
        changed on the fly.
        """
        self.gimp = gimp
        # list of lists: each list is ran in one task, last task is
        # interactive, other are not.
        self._bs = []
        self.vars = vars or {}

    def append(self, jobs=None, args=None, gimprc=None):
        """Append list of jobs, returns job-sequence id.
        kw are the sessions settings, like gimprc path.
        args are list of positional arguments.
        """
        if not jobs:
            jobs = []
        if type(jobs) not in (list, tuple):
            raise ValueError("jobs should be sequence")
        ret = len(self._bs)

        # create Session with attributes (for options)
        ses = Session(jobs) # list of jobs with session settings
        ses.gimprc = gimprc
        ses.set_args(args)

        self._bs.append(ses)
        return ret

    def _shsession(self, jobs, last):
        """Execute only jobs of one sequence on one gimp instance (one
        session), last is the opt of last sequence (last item in self._bs!)
        """
        if len(jobs) != 0:
            if not last:
                jobs = jobs.copy()
                # FIXME but final console message is not close, so until console is close
                # starting of next gimp is impossible, may be workaround with another
                # system() without waiting child PID
                jobs.append(u"'(gimp-quit 0)'")
                jobs.set_opt("-i")
            j = Gimpsh._prebatch(jobs, self.vars) # returns real list (not Session) of -b OPTs
        else:
            j = ""
        #jobs.set_opt("-s") # no splash window
        cl = u"%s %s %s" % (self.gimp, j, jobs.cmdline)
        utils.system(cl)

    def execone(self, jobsid):
        """Like _shsession but executed jobs are pointed by jobsid. If jobsid
        out of range, IndexError will be raised
        """
        self._shsession(self._bs[jobsid], jobsid==len(self._bs)-1)

    def execall(self, vars={}):
        """Executes all jobs sequence
        """
        for jobsid in xrange(len(self._bs)):
            self.execone(jobsid)

    @staticmethod
    def _prebatch(batches, vars={}):
        """Prepare batch for command line: quotes on win32, adds -b
        """
        if sys.platform ==  "win32":
            bs = [u"-b "+utils.quote_win32(b%vars) for b in batches]
        else:
            bs = [u"-b "+b%vars for b in batches]
        return u" ".join(bs)

Комментариев нет:

Отправить комментарий

Thanks for your posting!