def generate_enums_flags(file): all_enums = [] all_flags = [] def add_enum(gtype, a, b): nickname = type_name(gtype) all_enums.append(nickname) type_map(gtype, add_enum) return ffi.NULL # Enums type_map(type_from_name('GEnum'), add_enum) # Flags all_flags.append('VipsForeignPngFilter') print(f'Generating {file}...') with open(file, 'w') as f: f.write(' // Auto-generated enums\n') for name in all_enums: gtype = type_from_name(name) f.write(f' enum_<{name}>("{remove_prefix(name)}")') for value in values_for_enum(gtype): js_value = cppize(value) prefix = to_snake_case(name).upper() if prefix == 'VIPS_BAND_FORMAT': prefix = 'VIPS_FORMAT' elif prefix == 'VIPS_IMAGE_TYPE': prefix = 'VIPS_IMAGE' cpp_value = prefix + '_' + js_value.upper() if cpp_value == 'VIPS_INTERPRETATION_SRGB': cpp_value = 'VIPS_INTERPRETATION_sRGB' elif cpp_value == 'VIPS_INTERPRETATION_SCRGB': cpp_value = 'VIPS_INTERPRETATION_scRGB' f.write(f'\n .value("{js_value}", {cpp_value})') f.write(';\n\n') for name in all_flags: gtype = type_from_name(name) f.write(f' enum_<{name}>("{remove_prefix(name)}")') for value in values_for_flag(gtype): js_value = cppize(value) prefix = to_snake_case(name).upper() cpp_value = prefix + '_' + js_value.upper() f.write(f'\n .value("{js_value}", {cpp_value})') f.write(';\n\n')
def generate_enums(): # otherwise we're missing some enums vips_lib.vips_token_get_type() vips_lib.vips_saveable_get_type() vips_lib.vips_image_type_get_type() all_enums = [] def add_enum(gtype, a, b): nickname = type_name(gtype) all_enums.append(nickname) type_map(gtype, add_enum) return ffi.NULL type_map(type_from_name('GEnum'), add_enum) for name in all_enums: gtype = type_from_name(name) python_name = remove_prefix(name) if python_name not in xml_enums: continue node = xml_enums[python_name] enum_doc = node.find("goi:doc", namespace) print(f'') print(f'') print(f'class {python_name}(object):') print(f' """{python_name}.') if enum_doc is not None: print(f'') print(f'{enum_doc.text}') print(f'') print(f'Attributes:') print(f'') for value in values_for_enum(gtype): python_name = value.replace('-', '_') member = node.find(f"goi:member[@name='{python_name}']", namespace) member_doc = member.find("goi:doc", namespace) if member_doc is not None: text = member_doc.text print(f' {python_name.upper()} (str): {text}') print(f'') print(f' """') print(f'') for value in values_for_enum(gtype): python_name = value.replace('-', '_').upper() print(f' {python_name} = \'{value}\'')
def generate_operators(declarations_only=False): 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() for nickname in all_nicknames: print(generate_operation(nickname, declarations_only))
def generate_operators(declarations_only=False): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types intro = Introspect.get(nickname) # we are only interested in non-deprecated operations if (intro.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() for nickname in all_nicknames: print(generate_operation(nickname, declarations_only))
def gen_function_list(): 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() for nickname in all_nicknames: gen_function(nickname)
def generate_enums(): # otherwise we're missing some enums vips_lib.vips_token_get_type() vips_lib.vips_saveable_get_type() vips_lib.vips_image_type_get_type() all_enums = [] def add_enum(gtype, a, b): nickname = type_name(gtype) all_enums.append(nickname) type_map(gtype, add_enum) return ffi.NULL type_map(type_from_name('GEnum'), add_enum) for name in all_enums: gtype = type_from_name(name) php_name = remove_prefix(name) print('Generating {0}.php ...'.format(php_name)) with open('{0}.php'.format(php_name), 'w') as f: f.write(preamble) f.write('\n') f.write('namespace Jcupitt\\Vips;\n') f.write('\n') f.write('/**\n') f.write(' * The {0} enum.\n'.format(php_name)) f.write(class_header) f.write(' */\n') f.write('abstract class {0}\n'.format(php_name)) f.write('{\n') for value in values_for_enum(gtype): php_name = value.replace('-', '_').upper() if php_name in reserved_php_names: php_name = reserved_php_names[php_name] f.write(' const {0} = \'{1}\';\n'.format(php_name, value)) f.write('}\n')
def generate_sphinx_all(): """Generate sphinx documentation. This generates a .rst file for all auto-generated image methods. Use it to regenerate the docs with something like:: $ python -c \ "import pyvips; pyvips.Operation.generate_sphinx_all()" > x And copy-paste the file contents into doc/vimage.rst in the appropriate place. """ # generate list of all nicknames we can generate docstrings for all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: Operation.generate_sphinx(nickname) all_nicknames.append(nickname) except Error: pass type_map(gtype, add_nickname) return ffi.NULL type_map(type_from_name('VipsOperation'), add_nickname) all_nicknames.sort() # remove operations we have to wrap by hand exclude = ['scale', 'ifthenelse', 'bandjoin', 'bandrank'] all_nicknames = [x for x in all_nicknames if x not in exclude] # Output summary table print('.. class:: pyvips.Image\n') print(' .. rubric:: Methods\n') print(' .. autosummary::') print(' :nosignatures:\n') for nickname in all_nicknames: print(' ~{0}'.format(nickname)) print() # Output docs print() for nickname in all_nicknames: docstr = Operation.generate_sphinx(nickname) docstr = docstr.replace('\n', '\n ') print(' ' + docstr)
def generate_functions(file): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types intro = Introspect.get(nickname) # we are only interested in non-deprecated operations if (intro.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(key=lambda x: (bool(Introspect.get(x).member_x), x)) # enum, _const and multiple output functions are wrapped by hand filter = [ 'add', 'bandbool', 'bandjoin_const', 'boolean', 'boolean_const', 'complex', 'complexget', 'composite', 'divide', 'find_trim', 'flip', 'linear', 'math', 'math2', 'math2_const', 'morph', 'multiply', 'profile', 'project', 'relational', 'relational_const', 'remainder', 'remainder_const', 'rot', 'round', 'subtract' ] all_nicknames = [name for name in all_nicknames if name not in filter] print(f'Generating {file}...') with open(file, 'w') as f: f.write(' // Auto-generated (class-)functions\n') for nickname in all_nicknames: f.write(generate_operation(nickname) + '\n')
def generate_type_declarations(filename): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types intro = Introspect.get(nickname) # we are only interested in non-deprecated operations if (intro.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(key=lambda x: (bool(Introspect.get(x).member_x), x)) # filter functions we document by hand filter = [ 'composite', 'find_trim', 'profile', 'project', 'bandjoin_const', 'boolean_const', 'math2_const', 'relational_const', 'remainder_const' ] all_nicknames = [name for name in all_nicknames if name not in filter] with open(filename, 'a') as f: f.write(' class ImageAutoGen {\n') f.write( ' // THIS IS A GENERATED CLASS. DO NOT EDIT DIRECTLY.\n') for nickname in all_nicknames: f.write(generate_operation(nickname) + '\n') f.write(' }\n') f.write('}')
def generate_operators(declarations_only=False): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types intro = Introspect.get(nickname) # we are only interested in non-deprecated operations if (intro.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(key=lambda x: (bool(Introspect.get(x).member_x), x)) # some functions are wrapped by hand filter = [ 'add', 'bandjoin_const', 'boolean', 'composite', 'divide', 'ifthenelse', 'math2', 'multiply', 'relational', 'remainder', 'subtract' ] all_nicknames = [name for name in all_nicknames if name not in filter] print(preamble) for nickname in all_nicknames: print(generate_operation(nickname, declarations_only))
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 generate_enums_flags(gir_file, out_file): root = ET.parse(gir_file).getroot() namespace = {'goi': 'http://www.gtk.org/introspection/core/1.0'} # find all the enumerations/flags and make a dict for them xml_enums = {} for node in root.findall('goi:namespace/goi:enumeration', namespace): xml_enums[node.get('name')] = node xml_flags = {} for node in root.findall('goi:namespace/goi:bitfield', namespace): xml_flags[node.get('name')] = node all_nicknames = [] def add_enum(gtype, a, b): nickname = type_name(gtype) all_nicknames.append(nickname) gtype_to_js_param[gtype] = f'{remove_prefix(nickname)} | Enum' type_map(gtype, add_enum) return ffi.NULL # Enums type_map(type_from_name('GEnum'), add_enum) # Flags all_nicknames.append('VipsForeignPngFilter') gtype_to_js_param[ type_from_name('VipsForeignPngFilter' )] = f'{remove_prefix("VipsForeignPngFilter")} | Flag' with open('preamble_vips.d.ts', 'r') as f: preamble = f.read() with open(out_file, 'w') as f: f.write(preamble) for name in all_nicknames: gtype = type_from_name(name) name = remove_prefix(name) if name in xml_enums: is_enum = True node = xml_enums[name] elif name in xml_flags: is_enum = False node = xml_flags[name] else: continue enum_doc = node.find('goi:doc', namespace) if enum_doc is not None: text = enum_doc.text.replace('\n', '\n * ') f.write(' /**\n') f.write(f" * {text}\n") f.write(' */\n') f.write(f' export enum {name} {{\n') values = values_for_enum(gtype) if is_enum else values_for_flag( gtype) for i, value in enumerate(values): js_value = value.replace('-', '_') if i == 0 and (js_value == 'error' or js_value == 'notset'): continue member = node.find(f"goi:member[@name='{js_value}']", namespace) member_doc = member.find('goi:doc', namespace) if member_doc is not None: text = member_doc.text[:1].upper() + member_doc.text[1:] f.write(' /**\n') f.write(f' * {text}\n') f.write(' */\n') f.write(f" {js_value} = '{value}'") if i != len(values) - 1: f.write(',\n') f.write('\n }\n\n')
def gen_function_list(): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types intro = Introspect.get(nickname) # we are only interested in non-deprecated operations if (intro.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) # make list unique and sort all_nicknames = list(set(all_nicknames)) all_nicknames.sort() # make dict with overloads overloads = { 'bandbool': ['bandand', 'bandor', 'bandeor', 'bandmean'], 'bandjoin': ['bandjoin2'], 'bandjoin_const': ['bandjoin_const1'], 'boolean': ['andimage', 'orimage', 'eorimage', 'lshift', 'rshift'], 'cast': ['cast_uchar', 'cast_char', 'cast_ushort', 'cast_short' 'cast_uint', 'cast_int', 'cast_float', 'cast_double', 'cast_complex', 'cast_dpcomplex'], 'complex': ['polar', 'rect', 'conj'], 'complex2': ['cross_phase'], 'complexget': ['real', 'imag'], 'draw_circle': ['draw_circle1'], 'draw_flood': ['draw_flood1'], 'draw_line': ['draw_line1'], 'draw_mask': ['draw_mask1'], 'draw_rect': ['draw_rect1', 'draw_point', 'draw_point1'], 'extract_area': ['crop'], 'linear': ['linear1'], 'math': ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'exp', 'exp10', 'log', 'log10'], 'math2': ['pow', 'wop'], 'rank': ['median'], 'relational': ['equal', 'notequal', 'less', 'lesseq', 'more', 'moreeq'], 'remainder_const': ['remainder_const1'], 'round': ['floor', 'ceil', 'rint'], } overloads['boolean_const'] = [o + '_const' for o in overloads['boolean']] + ['boolean_const1'] + \ [o + '_const1' for o in overloads['boolean']] overloads['math2_const'] = [o + '_const' for o in overloads['boolean']] + ['math2_const1'] + \ [o + '_const1' for o in overloads['boolean']] overloads['relational_const'] = [o + '_const' for o in overloads['relational']] + ['relational_const1'] + \ [o + '_const1' for o in overloads['relational']] for nickname in all_nicknames: result = gen_function(nickname, overloads[nickname] if nickname in overloads else None) print(result)
# # call( "invert", # (options ? options : VImage::option())-> # set( "in", *this )-> # set( "out", &out ) ); # # return( out ); # } import argparse from pyvips import Introspect, Operation, GValue, Error, \ ffi, gobject_lib, type_map, type_from_name, nickname_find, type_name # TODO Move to pyvips.GValue stream_input_type = type_from_name('VipsStreami') stream_output_type = type_from_name('VipsStreamo') # turn a GType into a C++ type gtype_to_cpp = { GValue.gbool_type: 'bool', GValue.gint_type: 'int', GValue.gdouble_type: 'double', GValue.gstr_type: 'const char *', GValue.refstr_type: 'char *', GValue.gflags_type: 'int', GValue.image_type: 'VImage', stream_input_type: 'VStreamI', stream_output_type: 'VStreamO', GValue.array_int_type: 'std::vector<int>', GValue.array_double_type: 'std::vector<double>',
gtype_to_js_param = { GValue.gbool_type: 'boolean', GValue.gint_type: 'number', GValue.guint64_type: 'number', GValue.gdouble_type: 'number', GValue.gstr_type: 'string', GValue.refstr_type: 'string', GValue.gflags_type: 'Flag', GValue.image_type: 'Image', GValue.source_type: 'Source', GValue.target_type: 'Target', GValue.array_int_type: 'ArrayConstant', GValue.array_double_type: 'ArrayConstant', GValue.array_image_type: 'ArrayImage', GValue.blob_type: 'Blob', type_from_name('VipsInterpolate'): 'Interpolate' } gtype_to_js_return = { GValue.gbool_type: 'boolean', GValue.gint_type: 'number', GValue.guint64_type: 'number', GValue.gdouble_type: 'number', GValue.gstr_type: 'string', GValue.refstr_type: 'string', GValue.gflags_type: 'number', GValue.image_type: 'Image', GValue.array_int_type: 'number[]', GValue.array_double_type: 'number[]', GValue.array_image_type: 'Vector<Image>', GValue.blob_type: 'Uint8Array',
class GValue(object): """Wrap GValue in a Python class. This class wraps :class:`.GValue` in a convenient interface. You can use instances of this class to get and set :class:`.GObject` properties. On construction, :class:`.GValue` is all zero (empty). You can pass it to a get function to have it filled by :class:`.GObject`, or use init to set a type, set to set a value, then use it to set an object property. GValue lifetime is managed automatically. """ # look up some common gtypes at init for speed gbool_type = type_from_name('gboolean') gint_type = type_from_name('gint') gdouble_type = type_from_name('gdouble') gstr_type = type_from_name('gchararray') genum_type = type_from_name('GEnum') gflags_type = type_from_name('GFlags') gobject_type = type_from_name('GObject') image_type = type_from_name('VipsImage') array_int_type = type_from_name('VipsArrayInt') array_double_type = type_from_name('VipsArrayDouble') array_image_type = type_from_name('VipsArrayImage') refstr_type = type_from_name('VipsRefString') blob_type = type_from_name('VipsBlob') pyvips.vips_lib.vips_band_format_get_type() format_type = type_from_name('VipsBandFormat') if at_least_libvips(8, 6): pyvips.vips_lib.vips_blend_mode_get_type() blend_mode_type = type_from_name('VipsBlendMode') # map a gtype to the name of the corresponding Python type _gtype_to_python = { gbool_type: 'bool', gint_type: 'int', gdouble_type: 'float', gstr_type: 'str', refstr_type: 'str', genum_type: 'str', gflags_type: 'int', gobject_type: 'GObject', image_type: 'Image', array_int_type: 'list[int]', array_double_type: 'list[float]', array_image_type: 'list[Image]', blob_type: 'str' } @staticmethod 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>' @staticmethod def to_enum(gtype, value): """Turn a string into an enum value ready to be passed into libvips. """ if isinstance(value, basestring if _is_PY2 else str): enum_value = vips_lib.vips_enum_from_nick(b'pyvips', gtype, _to_bytes(value)) if enum_value < 0: raise Error('no value {0} in gtype {1} ({2})'.format( value, type_name(gtype), gtype)) else: enum_value = value return enum_value @staticmethod def from_enum(gtype, enum_value): """Turn an int back into an enum string. """ pointer = vips_lib.vips_enum_nick(gtype, enum_value) if pointer == ffi.NULL: raise Error('value not in enum') return _to_string(pointer) def __init__(self): # allocate memory for the gvalue which will be freed on GC self.pointer = ffi.new('GValue *') # logger.debug('GValue.__init__: pointer = %s', self.pointer) # and tag it to be unset on GC as well self.gvalue = ffi.gc(self.pointer, gobject_lib.g_value_unset) # logger.debug('GValue.__init__: gvalue = %s', self.gvalue) def set_type(self, gtype): """Set the type of a GValue. GValues have a set type, fixed at creation time. Use set_type to set the type of a GValue before assigning to it. GTypes are 32 or 64-bit integers (depending on the platform). See type_find. """ gobject_lib.g_value_init(self.gvalue, gtype) 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 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
from pyvips import Introspect, Operation, GValue, Error, \ ffi, gobject_lib, type_map, type_from_name, nickname_find, type_name # turn a GType into a C++ type gtype_to_cpp = { GValue.gbool_type: 'bool', GValue.gint_type: 'int', GValue.gdouble_type: 'double', GValue.gstr_type: 'const char *', GValue.refstr_type: 'char *', GValue.gflags_type: 'int', GValue.image_type: 'VImage', GValue.source_type: 'VSource', GValue.target_type: 'VTarget', GValue.guint64_type: 'guint64', type_from_name('VipsInterpolate'): 'VInterpolate', GValue.array_int_type: 'std::vector<int>', GValue.array_double_type: 'std::vector<double>', GValue.array_image_type: 'std::vector<VImage>', GValue.blob_type: 'VipsBlob *' } cplusplus_suffixes = ('*', '&') cplusplus_keywords = ('case', 'switch') # values for VipsArgumentFlags _REQUIRED = 1 _INPUT = 16 _OUTPUT = 32 _DEPRECATED = 64 _MODIFY = 128
# # call( "invert", # (options ? options : VImage::option())-> # set( "in", *this )-> # set( "out", &out ) ); # # return( out ); # } import argparse from pyvips import Introspect, Operation, GValue, Error, \ ffi, gobject_lib, type_map, type_from_name, nickname_find, type_name # TODO Move to pyvips.GValue source_type = type_from_name('VipsSource') target_type = type_from_name('VipsTarget') # turn a GType into a C++ type gtype_to_cpp = { GValue.gbool_type: 'bool', GValue.gint_type: 'int', GValue.gdouble_type: 'double', GValue.gstr_type: 'const char *', GValue.refstr_type: 'char *', GValue.gflags_type: 'int', GValue.image_type: 'VImage', source_type: 'VSource', target_type: 'VTarget', GValue.array_int_type: 'std::vector<int>', GValue.array_double_type: 'std::vector<double>',