#!/usr/bin/python import logging import sys from gi.repository import GLib from gi.repository import GObject # you might need this in your .bashrc # export GI_TYPELIB_PATH=$VIPSHOME/lib/girepository-1.0 from gi.repository import Vips class Error(Exception): """An error from vips. message -- a high-level description of the error detail -- a string with some detailed diagnostics """ def __init__(self, message, detail = None): self.message = message if detail == None: detail = Vips.error_buffer() Vips.error_clear() self.detail = detail logging.debug('vips: Error %s %s', self.message, self.detail) def __str__(self): return '%s %s' % (self.message, self.detail) class Argument: def __init__(self, op, prop): self.op = op; self.prop = prop; self.name = prop.name; self.flags = op.get_argument_flags(self.name) self.priority = op.get_argument_priority(self.name) self.assigned = op.get_argument_assigned(self.name) def _call_base(name, self, required, optional): logging.debug('_call_base name=%s, self=%s, required=%s optional=%s' % (name, self, required, optional)) try: op = Vips.Operation.new(name) except TypeError, e: raise Error('No such operator.') # find all the args for this op, sort into priority order args = [Argument(op, x) for x in op.props] args.sort(lambda a, b: a.priority - b.priority) enm = Vips.ArgumentFlags # find all required, unassigned input args required_input = [x for x in args if x.flags & enm.INPUT and x.flags & enm.REQUIRED and not x.assigned] # do we have a non-NULL self pointer? this is used to set the first # compatible input arg if self != None: found = False for x in required_input: if GObject.type_is_a(self, x.prop.value_type): op.props.__setattr__(x.name, self) required_input.remove(x) found = True break if not found: raise Error('Bad arguments.', 'No %s argument to %s.' % (str(self.__class__), name)) if len(required_input) != len(required): raise Error('Wrong number of arguments.', '"%s" needs %d arguments, you supplied %d' % (name, len(required_input), len(required))) for i in range(len(required_input)): print 'assigning', required[i], 'to', required_input[i].name print required_input[i].name, 'needs a', required_input[i].prop.value_type op.props.__setattr__(required_input[i].name, required[i]) # find all optional, unassigned input args ... just need the names optional_input = [x.name for x in args if x.flags & enm.INPUT and not x.flags & enm.REQUIRED and not x.assigned] for key in optional.keys(): if not key in optional_input: raise Error('Unknown argument.', 'Operator %s has no argument %s' % (name, key)) # set optional input args for key in optional.keys(): op.props.__setattr__(key, optional[key]) # call op2 = Vips.cache_operation_build(op) if op2 == None: raise Error('Error calling operator %s.' % name) # find all required output args ... just need the names # we can't check assigned here (since we captured the value before the call) # but the getattr will test that for us anyway required_output = [x.name for x in args if x.flags & enm.OUTPUT and x.flags & enm.REQUIRED] # gather output args out = [] for x in required_output: out.append(op2.props.__getattribute__(x)) # find all optional output args ... just need the names optional_output = [x.name for x in args if x.flags & enm.OUTPUT and not x.flags & enm.REQUIRED] for x in optional.keys(): if x in optional_output: out.append(op2.props.__getattribute__(x)) if len(out) == 1: out = out[0] # unref everything now we have refs to all outputs we want op2.unref_outputs() return out # general user entrypoint def call(name, *args, **kwargs): return _call_base(name, None, args, kwargs) # from getattr ... try to run the attr as a method def _call_instance(self, name, args, kwargs): return _call_base(name, self, args, kwargs) class Image(Vips.Image): def __init__(self, filename = None, mode = None): Vips.Image.__init__(self) if filename: self.props.filename = filename if not mode: mode = "rd" if mode: self.props.mode = mode if self.build() != 0: print 'build failed' raise Error('Unable to build image') def __getattr__(self, name): logging.debug('vipsimage: __getattr__ %s' % name) return lambda *args, **kwargs: _call_instance(self, name, args, kwargs) # start up vips! Vips.init(sys.argv[0])