def call(operation_name, *args, **kwargs): """Call a libvips operation. Use this method to call any libvips operation. For example:: black_image = pyvips.Operation.call('black', 10, 10) See the Introduction for notes on how this works. """ logger.debug('VipsOperation.call: operation_name = %s', operation_name) # logger.debug('VipsOperation.call: args = %s, kwargs =%s', # args, kwargs) # pull out the special string_options kwarg string_options = kwargs.pop('string_options', '') logger.debug('VipsOperation.call: string_options = %s', string_options) op = Operation.new_from_name(operation_name) arguments = op.get_args() # logger.debug('arguments = %s', arguments) # make a thing to quickly get flags from an arg name flags_from_name = {} # count required input args n_required = 0 for name, flags in arguments: flags_from_name[name] = flags if ((flags & _INPUT) != 0 and (flags & _REQUIRED) != 0 and (flags & _DEPRECATED) == 0): n_required += 1 if n_required != len(args): raise Error('unable to call {0}: {1} arguments given, ' 'but {2} required'.format(operation_name, len(args), n_required)) # the first image argument is the thing we expand constants to # match ... look inside tables for images, since we may be passing # an array of image as a single param match_image = _find_inside(lambda x: isinstance(x, pyvips.Image), args) logger.debug('VipsOperation.call: match_image = %s', match_image) # set any string options before any args so they can't be # overridden if not op.set_string(string_options): raise Error('unable to call {0}'.format(operation_name)) # set required and optional args n = 0 for name, flags in arguments: if ((flags & _INPUT) != 0 and (flags & _REQUIRED) != 0 and (flags & _DEPRECATED) == 0): op.set(name, flags, match_image, args[n]) n += 1 for name, value in kwargs.items(): if name not in flags_from_name: raise Error('{0} does not support argument ' '{1}'.format(operation_name, name)) op.set(name, flags_from_name[name], match_image, value) # build operation vop = vips_lib.vips_cache_operation_build(op.pointer) if vop == ffi.NULL: raise Error('unable to call {0}'.format(operation_name)) op = Operation(vop) # fetch required output args, plus modified input images result = [] for name, flags in arguments: if ((flags & _OUTPUT) != 0 and (flags & _REQUIRED) != 0 and (flags & _DEPRECATED) == 0): result.append(op.get(name)) if (flags & _INPUT) != 0 and (flags & _MODIFY) != 0: result.append(op.get(name)) # fetch optional output args opts = {} for name, value in kwargs.items(): flags = flags_from_name[name] if ((flags & _OUTPUT) != 0 and (flags & _REQUIRED) == 0 and (flags & _DEPRECATED) == 0): opts[name] = op.get(name) vips_lib.vips_object_unref_outputs(op.object) if len(opts) > 0: result.append(opts) if len(result) == 0: result = None elif len(result) == 1: result = result[0] logger.debug('VipsOperation.call: result = %s', result) return result
def call(operation_name, *args, **kwargs): """Call a libvips operation. Use this method to call any libvips operation. For example:: black_image = pyvips.Operation.call('black', 10, 10) See the Introduction for notes on how this works. """ logger.debug('VipsOperation.call: operation_name = %s', operation_name) # logger.debug('VipsOperation.call: args = %s, kwargs =%s', # args, kwargs) intro = Introspect.get(operation_name) if len(intro.required_input) != len(args): raise Error('{0} needs {1} arguments, but {2} given'.format( operation_name, len(intro.required_input), len(args))) op = Operation.new_from_name(operation_name) # set any string options before any args so they can't be # overridden string_options = kwargs.pop('string_options', '') if not op.set_string(string_options): raise Error('unable to call {0}'.format(operation_name)) # the first image argument is the thing we expand constants to # match ... look inside tables for images, since we may be passing # an array of images as a single param match_image = _find_inside(lambda x: isinstance(x, pyvips.Image), args) logger.debug('VipsOperation.call: match_image = %s', match_image) # collect a list of all input references here # we can't use a set because set elements are unique under "==", and # Python checks memoryview equality with hash functions, not pointer # equality references = [] # does a list contain an element using pointer equality # we can't use "in" since that uses "==", which means hash equality def contains(array, x): for y in array: if id(x) == id(y): return True return False def add_reference(x): if isinstance(x, pyvips.Image): for i in x._references: if not contains(references, i): references.append(i) return False # set required input args for name, value in zip(intro.required_input, args): _find_inside(add_reference, value) op.set(name, intro.details[name]['flags'], match_image, value) # set any optional args for name in kwargs: if (name not in intro.optional_input and name not in intro.optional_output): raise Error( '{0} does not support optional argument {1}'.format( operation_name, name)) value = kwargs[name] details = intro.details[name] if (details['flags'] & _DEPRECATED) != 0: logger.info('{0} argument {1} is deprecated', operation_name, name) _find_inside(add_reference, value) op.set(name, details['flags'], match_image, value) # build operation vop = vips_lib.vips_cache_operation_build(op.pointer) if vop == ffi.NULL: vips_lib.vips_object_unref_outputs(op.vobject) raise Error('unable to call {0}'.format(operation_name)) op = Operation(vop) # attach all input refs to output x def set_reference(x): if isinstance(x, pyvips.Image): x._references.extend(references) return False # fetch required output args (plus modified input images) result = [] for name in intro.required_output: value = op.get(name) _find_inside(set_reference, value) result.append(value) # fetch optional output args opts = {} for name in intro.optional_output: if name in kwargs: value = op.get(name) _find_inside(set_reference, value) opts[name] = value if len(opts) > 0: result.append(opts) vips_lib.vips_object_unref_outputs(op.vobject) if len(result) == 0: result = None elif len(result) == 1: result = result[0] logger.debug('VipsOperation.call: result = %s', result) return result