def get_cpp_type(gtype): """Map a gtype to C++ type name we use to represent it. """ if gtype in gtype_to_cpp: return gtype_to_cpp[gtype] fundamental = gobject_lib.g_type_fundamental(gtype) if fundamental in gtype_to_cpp: return gtype_to_cpp[fundamental] return '<unknown type>'
def gtype_to_python(gtype): """Map a gtype to the name of the Python type we use to represent it. """ fundamental = gobject_lib.g_type_fundamental(gtype) if gtype in GValue._gtype_to_python: return GValue._gtype_to_python[gtype] if fundamental in GValue._gtype_to_python: return GValue._gtype_to_python[fundamental] return '<unknown type>'
def gtype_to_php(gtype, result=False): """Map a gtype to PHP type name we use to represent it. """ fundamental = gobject_lib.g_type_fundamental(gtype) gtype_map = gtype_to_php_result if result else gtype_to_php_arg if gtype in gtype_map: return gtype_map[gtype] if fundamental in gtype_map: return gtype_map[fundamental] return '<unknown type>'
def get_cpp_type(gtype, param=False): """Map a gtype to C++ type name we use to represent it. """ lookup = gtype_to_cpp_param if param else gtype_to_cpp_return if gtype in lookup: return lookup[gtype] fundamental = gobject_lib.g_type_fundamental(gtype) if fundamental in lookup: return lookup[fundamental] return '<unknown type>'
def generate_operation(operation_name): intro = Introspect.get(operation_name) result = ' * @method ' if intro.member_x is None: result += 'static ' if len(intro.required_output) == 0: result += 'void ' elif len(intro.required_output) == 1: arg = intro.required_output[0] details = intro.details[arg] result += '{0} '.format(gtype_to_php(details['type'], True)) else: # we generate a Returns: block for this case, see below result += 'array ' result += '{0}('.format(operation_name) for name in intro.method_args: details = intro.details[name] result += '{0} ${1}, '.format(gtype_to_php(details['type']), name) result += 'array $options = []) ' description = intro.description result += description[0].upper() + description[1:] + '.\n' # find any Enums we've referenced and output @see lines for them for name in intro.required_output + intro.method_args: details = intro.details[name] fundamental = gobject_lib.g_type_fundamental(details['type']) if fundamental != GValue.genum_type: continue result += ' * @see {0} for possible values for ${1}\n'.format( remove_prefix(type_name(details['type'])), name) if len(intro.required_output) > 1: result += ' * Return array with: [\n' for name in intro.required_output: details = intro.details[name] result += ' * \'{0}\' => @type {1} {2}\n'.format( name, gtype_to_php(details['type']), details['blurb'][0].upper() + details['blurb'][1:]) result += ' * ];\n' result += ' * @throws Exception\n' return result
def get_cpp_type(gtype): """Map a gtype to C++ type name we use to represent it. """ if gtype in gtype_to_cpp: return gtype_to_cpp[gtype] fundamental = gobject_lib.g_type_fundamental(gtype) # enum params use the C name as their name if fundamental == GValue.genum_type: return type_name(gtype) if fundamental in gtype_to_cpp: return gtype_to_cpp[fundamental] return '<unknown type>'
def get_js_type(gtype, param=False): """Map a gtype to JS type name we use to represent it. """ lookup = gtype_to_js_param if param else gtype_to_js_return if gtype in lookup: # we allow constants in image parameter types if param and (gtype == GValue.image_type or gtype == GValue.array_image_type): return lookup[gtype] + ' | ArrayConstant' return lookup[gtype] fundamental = gobject_lib.g_type_fundamental(gtype) if fundamental in lookup: return lookup[fundamental] return '<unknown type>'
def gtype_to_python(gtype): """Map a gtype to the name of the Python type we use to represent it. """ fundamental = gobject_lib.g_type_fundamental(gtype) # enums can be strings or class members ... we want to generate a union # type if fundamental == GValue.genum_type: name = type_name(gtype) if name.startswith('Vips'): name = name[4:] return "Union[str, %s]" % name if gtype in GValue._gtype_to_python: return GValue._gtype_to_python[gtype] if fundamental in GValue._gtype_to_python: return GValue._gtype_to_python[fundamental] return '<unknown type>'
def get(self): """Get the contents of a GValue. The contents of the GValue are read out as a Python type. """ # logger.debug('GValue.get: self = %s', self) gtype = self.gvalue.g_type fundamental = gobject_lib.g_type_fundamental(gtype) result = None if gtype == GValue.gbool_type: result = bool(gobject_lib.g_value_get_boolean(self.gvalue)) elif gtype == GValue.gint_type: result = gobject_lib.g_value_get_int(self.gvalue) elif gtype == GValue.gdouble_type: result = gobject_lib.g_value_get_double(self.gvalue) elif fundamental == GValue.genum_type: return GValue.from_enum(gtype, gobject_lib.g_value_get_enum(self.gvalue)) elif fundamental == GValue.gflags_type: result = gobject_lib.g_value_get_flags(self.gvalue) elif gtype == GValue.gstr_type: pointer = gobject_lib.g_value_get_string(self.gvalue) if pointer != ffi.NULL: result = _to_string(pointer) elif gtype == GValue.refstr_type: psize = ffi.new('size_t *') pointer = vips_lib.vips_value_get_ref_string(self.gvalue, psize) # psize[0] will be number of bytes in string, but just assume it's # NULL-terminated result = _to_string(pointer) elif gtype == GValue.image_type: # g_value_get_object() will not add a ref ... that is # held by the gvalue go = gobject_lib.g_value_get_object(self.gvalue) vi = ffi.cast('VipsImage *', go) # we want a ref that will last with the life of the vimage: # this ref is matched by the unref that's attached to finalize # by Image() gobject_lib.g_object_ref(go) result = pyvips.Image(vi) elif gtype == GValue.array_int_type: pint = ffi.new('int *') array = vips_lib.vips_value_get_array_int(self.gvalue, pint) result = [] for i in range(0, pint[0]): result.append(array[i]) elif gtype == GValue.array_double_type: pint = ffi.new('int *') array = vips_lib.vips_value_get_array_double(self.gvalue, pint) result = [] for i in range(0, pint[0]): result.append(array[i]) elif gtype == GValue.array_image_type: pint = ffi.new('int *') array = vips_lib.vips_value_get_array_image(self.gvalue, pint) result = [] for i in range(0, pint[0]): vi = array[i] gobject_lib.g_object_ref(vi) image = pyvips.Image(vi) result.append(image) elif gtype == GValue.blob_type: psize = ffi.new('size_t *') array = vips_lib.vips_value_get_blob(self.gvalue, psize) buf = ffi.cast('char*', array) result = ffi.unpack(buf, psize[0]) else: raise Error('unsupported gtype for get {0}'.format( type_name(gtype))) return result
def set(self, value): """Set a GValue. The value is converted to the type of the GValue, if possible, and assigned. """ # logger.debug('GValue.set: value = %s', value) gtype = self.gvalue.g_type fundamental = gobject_lib.g_type_fundamental(gtype) if gtype == GValue.gbool_type: gobject_lib.g_value_set_boolean(self.gvalue, value) elif gtype == GValue.gint_type: gobject_lib.g_value_set_int(self.gvalue, int(value)) elif gtype == GValue.gdouble_type: gobject_lib.g_value_set_double(self.gvalue, value) elif fundamental == GValue.genum_type: gobject_lib.g_value_set_enum(self.gvalue, GValue.to_enum(gtype, value)) elif fundamental == GValue.gflags_type: gobject_lib.g_value_set_flags(self.gvalue, value) elif gtype == GValue.gstr_type: gobject_lib.g_value_set_string(self.gvalue, _to_bytes(value)) elif gtype == GValue.refstr_type: vips_lib.vips_value_set_ref_string(self.gvalue, _to_bytes(value)) elif fundamental == GValue.gobject_type: gobject_lib.g_value_set_object(self.gvalue, value.pointer) elif gtype == GValue.array_int_type: if isinstance(value, numbers.Number): value = [value] array = ffi.new('int[]', value) vips_lib.vips_value_set_array_int(self.gvalue, array, len(value)) elif gtype == GValue.array_double_type: if isinstance(value, numbers.Number): value = [value] array = ffi.new('double[]', value) vips_lib.vips_value_set_array_double(self.gvalue, array, len(value)) elif gtype == GValue.array_image_type: if isinstance(value, pyvips.Image): value = [value] vips_lib.vips_value_set_array_image(self.gvalue, len(value)) array = vips_lib.vips_value_get_array_image(self.gvalue, ffi.NULL) for i, image in enumerate(value): gobject_lib.g_object_ref(image.pointer) array[i] = image.pointer elif gtype == GValue.blob_type: # we need to set the blob to a copy of the string that vips_lib # can own memory = glib_lib.g_malloc(len(value)) ffi.memmove(memory, value, len(value)) # this is horrible! # # * in API mode, we must have 8.6+ and use set_blob_free to # attach the metadata to avoid leaks # * pre-8.6, we just pass a NULL free pointer and live with the # leak # # this is because in API mode you can't pass a builtin (what # vips_lib.g_free() becomes) as a parameter to ffi.callback(), and # vips_value_set_blob() needs a callback for arg 2 # # additionally, you can't make a py def which calls g_free() and # then use the py def in the callback, since libvips will trigger # these functions during cleanup, and py will have shut down by # then and you'll get a segv if at_least_libvips(8, 6): vips_lib.vips_value_set_blob_free(self.gvalue, memory, len(value)) else: if pyvips.API_mode: vips_lib.vips_value_set_blob(self.gvalue, ffi.NULL, memory, len(value)) else: vips_lib.vips_value_set_blob(self.gvalue, glib_lib.g_free, memory, len(value)) else: raise Error( 'unsupported gtype for set {0}, fundamental {1}'.format( type_name(gtype), type_name(fundamental)))
def generate_operation(operation_name): op = Operation.new_from_name(operation_name) # we are only interested in non-deprecated args args = [[name, flags] for name, flags in op.get_args() if not flags & _DEPRECATED] # find the first required input image arg, if any ... that will be self member_x = None for name, flags in args: if ((flags & _INPUT) != 0 and (flags & _REQUIRED) != 0 and op.get_typeof(name) == GValue.image_type): member_x = name break required_input = [ name for name, flags in args if (flags & _INPUT) != 0 and (flags & _REQUIRED) != 0 and name != member_x ] required_output = [ name for name, flags in args if ((flags & _OUTPUT) != 0 and (flags & _REQUIRED) != 0) or ( (flags & _INPUT) != 0 and (flags & _REQUIRED) != 0 and (flags & _MODIFY) != 0) ] result = ' * @method ' if member_x is None: result += 'static ' if len(required_output) == 0: result += 'void ' elif len(required_output) == 1: result += '{0} '.format( gtype_to_php(op.get_typeof(required_output[0]), True)) else: # we generate a Returns: block for this case, see below result += 'array ' result += '{0}('.format(operation_name) for name in required_input: gtype = op.get_typeof(name) result += '{0} ${1}, '.format(gtype_to_php(gtype), name) result += 'array $options = []) ' description = op.get_description() result += description[0].upper() + description[1:] + '.\n' # find any Enums we've referenced and output @see lines for them for name in required_output + required_input: gtype = op.get_typeof(name) fundamental = gobject_lib.g_type_fundamental(gtype) if fundamental != GValue.genum_type: continue result += ' * @see {0} for possible values for ${1}\n'.format( remove_prefix(type_name(gtype)), name) if len(required_output) > 1: result += ' * Return array with: [\n' for name in required_output: gtype = op.get_typeof(name) blurb = op.get_blurb(name) result += ' * \'{0}\' => @type {1} {2}\n'.format( name, gtype_to_php(gtype), blurb[0].upper() + blurb[1:]) result += ' * ];\n' result += ' * @throws Exception\n' return result
def generate_auto_doc(filename): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types op = Operation.new_from_name(nickname) # we are only interested in non-deprecated operations if (op.get_flags() & _OPERATION_DEPRECATED) == 0: all_nicknames.append(nickname) except Error: pass type_map(gtype, add_nickname) return ffi.NULL type_map(type_from_name('VipsOperation'), add_nickname) # add 'missing' synonyms by hand all_nicknames.append('crop') # make list unique and sort all_nicknames = list(set(all_nicknames)) all_nicknames.sort() # these have hand-written methods, don't autodoc them no_generate = [ 'bandjoin', 'bandrank', 'ifthenelse', 'add', 'subtract', 'multiply', 'divide', 'remainder' ] all_nicknames = [x for x in all_nicknames if x not in no_generate] print('Generating {0} ...'.format(filename)) with open(filename, 'w') as f: f.write(preamble) f.write('\n') f.write('namespace Jcupitt\\Vips;\n') f.write('\n') f.write('/**\n') f.write(' * Autodocs for the Image class.\n') f.write(class_header) f.write(' *\n') for nickname in all_nicknames: f.write(generate_operation(nickname)) f.write(' *\n') # all magic properties tmp_file = Image.new_temp_file('%s.v') all_properties = tmp_file.get_fields() for name in all_properties: php_name = name.replace('-', '_') gtype = tmp_file.get_typeof(name) fundamental = gobject_lib.g_type_fundamental(gtype) f.write(' * @property {0} ${1} {2}\n'.format( gtype_to_php(gtype), php_name, tmp_file.get_blurb(name))) if fundamental == GValue.genum_type: f.write(' * @see {0} for possible values\n'.format( remove_prefix(type_name(gtype)))) f.write(' */\n') f.write('abstract class ImageAutodoc\n') f.write('{\n') f.write('}\n')
def set(self, value): """Set a GValue. The value is converted to the type of the GValue, if possible, and assigned. """ # logger.debug('GValue.set: value = %s', value) gtype = self.gvalue.gtype fundamental = gobject_lib.g_type_fundamental(gtype) if gtype == GValue.gbool_type: gobject_lib.g_value_set_boolean(self.gvalue, value) elif gtype == GValue.gint_type: gobject_lib.g_value_set_int(self.gvalue, int(value)) elif gtype == GValue.gdouble_type: gobject_lib.g_value_set_double(self.gvalue, value) elif fundamental == GValue.genum_type: gobject_lib.g_value_set_enum(self.gvalue, GValue.to_enum(gtype, value)) elif fundamental == GValue.gflags_type: gobject_lib.g_value_set_flags(self.gvalue, value) elif gtype == GValue.gstr_type or gtype == GValue.refstr_type: gobject_lib.g_value_set_string(self.gvalue, _to_bytes(value)) elif fundamental == GValue.gobject_type: gobject_lib.g_value_set_object(self.gvalue, value.pointer) elif gtype == GValue.array_int_type: if isinstance(value, numbers.Number): value = [value] array = ffi.new('int[]', value) vips_lib.vips_value_set_array_int(self.gvalue, array, len(value)) elif gtype == GValue.array_double_type: if isinstance(value, numbers.Number): value = [value] array = ffi.new('double[]', value) vips_lib.vips_value_set_array_double(self.gvalue, array, len(value)) elif gtype == GValue.array_image_type: if isinstance(value, pyvips.Image): value = [value] vips_lib.vips_value_set_array_image(self.gvalue, len(value)) array = vips_lib.vips_value_get_array_image(self.gvalue, ffi.NULL) for i, image in enumerate(value): gobject_lib.g_object_ref(image.pointer) array[i] = image.pointer elif gtype == GValue.blob_type: # we need to set the blob to a copy of the string that vips_lib # can own memory = glib_lib.g_malloc(len(value)) ffi.memmove(memory, value, len(value)) vips_lib.vips_value_set_blob(self.gvalue, glib_lib.g_free, memory, len(value)) else: raise Error( 'unsupported gtype for set {0}, fundamental {1}'.format( type_name(gtype), type_name(fundamental)))