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 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
def gen_function(operation_name, overloads): intro = Introspect.get(operation_name) c_operations = 'vips_{}()'.format(operation_name) if overloads: c_operations += ', ' + (', '.join('vips_{}()'.format(n) for n in overloads)) result = '<row>\n' result += ' <entry>{}</entry>\n'.format(operation_name) result += ' <entry>{}</entry>\n'.format(intro.description.capitalize()) result += ' <entry>{}</entry>\n'.format(c_operations) result += '</row>' return result
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_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_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_operation(operation_name, indent=' '): intro = Introspect.get(operation_name) required_output = [ name for name in intro.required_output if name != intro.member_x ] has_input = len(intro.method_args) >= 1 has_output = len(required_output) >= 1 has_optional_options = len(intro.doc_optional_input) + len( intro.doc_optional_output) >= 1 # Add a comment block with some additional markings (@param, @return) result = f'\n{indent}/**' result += f'\n{indent} * {intro.description.capitalize()}.' for name in intro.method_args: result += f"\n{indent} * @param {js_name(name)} {intro.details[name]['blurb']}." if has_optional_options: result += f'\n{indent} * @param options Optional options.' if has_output: result += f"\n{indent} * @return {intro.details[required_output[0]]['blurb']}." result += f'\n{indent} */\n' if intro.member_x is None: result += f'{indent}static ' else: result += indent js_operation = to_camel_case(operation_name) result += f'{js_operation}(' result += ', '.join([ f"{js_name(x)}: {get_js_type(intro.details[x]['type'], True)}" for x in intro.method_args ]) if has_optional_options: if has_input: result += ', ' result += 'options?: {' for name in intro.doc_optional_input: result += f'\n{indent} /**' result += f"\n{indent} * {intro.details[name]['blurb'].capitalize()}." result += f'\n{indent} */' result += f"\n{indent} {js_name(name)}?: {get_js_type(intro.details[name]['type'], True)}" for name in intro.doc_optional_output: result += f'\n{indent} /**' result += f"\n{indent} * {intro.details[name]['blurb'].capitalize()} (output)." result += f'\n{indent} */' result += f"\n{indent} {js_name(name)}?: {get_js_type(intro.details[name]['type'], False)} | undefined" result += f'\n{indent}}}' result += '): ' # the first output arg will be used as the result if has_output: js_type = get_js_type(intro.details[required_output[0]]['type'], False) result += f'{js_type};' else: result += 'void;' return result
def generate_operation(operation_name, declaration_only=False): intro = Introspect.get(operation_name) required_output = [ name for name in intro.required_output if name != intro.member_x ] has_output = len(required_output) >= 1 # Add a C++ style comment block with some additional markings (@param, # @return) if declaration_only: result = f'\n/**\n * {intro.description.capitalize()}.' if len(intro.optional_input) > 0: result += '\n *\n * **Optional parameters**' for name in intro.optional_input: details = intro.details[name] result += f'\n * - **{cppize(name)}** -- ' result += f'{details["blurb"]}, ' result += f'{get_cpp_type(details["type"])}.' result += '\n *' for name in intro.method_args: details = intro.details[name] result += f'\n * @param {cppize(name)} {details["blurb"]}.' if has_output: # skip the first element for name in required_output[1:]: details = intro.details[name] result += f'\n * @param {cppize(name)} {details["blurb"]}.' result += '\n * @param options Set of options.' if has_output: details = intro.details[required_output[0]] result += f'\n * @return {details["blurb"]}.' result += '\n */\n' else: result = '\n' if intro.member_x is None and declaration_only: result += 'static ' if has_output: # the first output arg will be used as the result cpp_type = get_cpp_type(intro.details[required_output[0]]['type']) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}' else: result += 'void ' if not declaration_only: result += 'VImage::' cplusplus_operation = operation_name if operation_name in cplusplus_keywords: cplusplus_operation += '_image' result += f'{cplusplus_operation}( ' for name in intro.method_args: details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}{cppize(name)}, ' # output params are passed by reference if has_output: # skip the first element for name in required_output[1:]: details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}*{cppize(name)}, ' result += f'VOption *options {"= 0 " if declaration_only else ""})' # if no 'this' available, it's a class method and they are all const if intro.member_x is not None: result += ' const' if declaration_only: result += ';' return result result += '\n{\n' if has_output: # the first output arg will be used as the result name = required_output[0] cpp_type = get_cpp_type(intro.details[name]['type']) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f' {cpp_type}{spacing}{cppize(name)};\n\n' result += f' call( "{operation_name}",\n' result += f' (options ? options : VImage::option())' if intro.member_x is not None: result += f'->\n' result += f' set( "{intro.member_x}", *this )' all_required = intro.method_args if has_output: # first element needs to be passed by reference arg = cppize(required_output[0]) result += f'->\n' result += f' set( "{required_output[0]}", &{arg} )' # append the remaining list all_required += required_output[1:] for name in all_required: arg = cppize(name) result += f'->\n' result += f' set( "{name}", {arg} )' result += ' );\n' if has_output: result += f'\n' result += f' return( {required_output[0]} );\n' result += '}' return result
def generate_operation(operation_name): intro = Introspect.get(operation_name) required_output = [ name for name in intro.required_output if name != intro.member_x ] is_void = len(required_output) == 0 has_input = len(intro.method_args) >= 1 has_multiple_output = len(required_output) > 1 has_optional_options = len(intro.optional_input) + len( intro.optional_output) >= 1 function_type = 'function' if intro.member_x else 'class_function' result = '' cplusplus_operation = operation_name if operation_name in cplusplus_keywords: cplusplus_operation += '_image' padding = ' ' * 9 if intro.member_x else ' ' * 15 result += f' .{function_type}("{to_camel_case(operation_name)}", &Image::{cplusplus_operation}' if has_multiple_output: result += ', allow_raw_pointers())\n' else: result += ')' if not has_optional_options: return result # need to overload the function without optional options result += f'\n .{function_type}("{to_camel_case(operation_name)}", optional_override([](' if intro.member_x is not None: result += 'const Image &image' if has_input or len(required_output) > 1: result += ', ' for i, name in enumerate(intro.method_args): details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}{cppize(name)}' if i != len(intro.method_args) - 1: result += ', ' # output params are passed by reference if has_multiple_output: # skip the first element for i, name in enumerate(required_output[1:]): details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}*{cppize(name)}' if i != len(required_output) - 2: result += ', ' result += ') {\n' result += f'{padding} ' result += f"{'' if is_void else 'return '}" result += f"{'Image::' if intro.member_x is None else 'image.'}{cplusplus_operation}(" for i, name in enumerate(intro.method_args): result += cppize(name) if i != len(intro.method_args) - 1: result += ', ' if has_multiple_output: # skip the first element for i, name in enumerate(required_output[1:]): result += cppize(name) if i != len(required_output) - 2: result += ', ' result += ');\n' result += f' {padding}}})' if has_multiple_output: result += ', allow_raw_pointers())' else: result += ')' return result
def generate_operation(operation_name, declaration_only=False): intro = Introspect.get(operation_name) required_output = [ name for name in intro.required_output if name != intro.member_x ] has_output = len(required_output) >= 1 # Add a C++ style comment block with some additional markings (@param, # @return) if declaration_only: result = '\n/**\n * {}.'.format(intro.description.capitalize()) for name in intro.method_args: result += '\n * @param {} {}.' \ .format(cppize(name), intro.details[name]['blurb']) if has_output: # skip the first element for name in required_output[1:]: result += '\n * @param {} {}.' \ .format(cppize(name), intro.details[name]['blurb']) result += '\n * @param options Optional options.' if has_output: result += '\n * @return {}.' \ .format(intro.details[required_output[0]]['blurb']) result += '\n */\n' else: result = '\n' if intro.member_x is None and declaration_only: result += 'static ' if has_output: # the first output arg will be used as the result cpp_type = get_cpp_type(intro.details[required_output[0]]['type']) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += '{0}{1}'.format(cpp_type, spacing) else: result += 'void ' if not declaration_only: result += 'VImage::' cplusplus_operation = operation_name if operation_name in cplusplus_keywords: cplusplus_operation += '_image' result += '{0}( '.format(cplusplus_operation) for name in intro.method_args: details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += '{0}{1}{2}, '.format(cpp_type, spacing, cppize(name)) # output params are passed by reference if has_output: # skip the first element for name in required_output[1:]: details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += '{0}{1}*{2}, '.format(cpp_type, spacing, cppize(name)) result += 'VOption *options {0})'.format( '= 0 ' if declaration_only else '') # if no 'this' available, it's a class method and they are all const if intro.member_x is not None: result += ' const' if declaration_only: result += ';' return result result += '\n{\n' if has_output: # the first output arg will be used as the result name = required_output[0] cpp_type = get_cpp_type(intro.details[name]['type']) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += ' {0}{1}{2};\n\n'.format(cpp_type, spacing, cppize(name)) result += ' call( "{0}",\n'.format(operation_name) result += ' (options ? options : VImage::option())' if intro.member_x is not None: result += '->\n' result += ' set( "{0}", *this )'.format(intro.member_x) all_required = intro.method_args if has_output: # first element needs to be passed by reference arg = cppize(required_output[0]) result += '->\n' result += ' set( "{0}", &{1} )' \ .format(required_output[0], arg) # append the remaining list all_required += required_output[1:] for name in all_required: arg = cppize(name) result += '->\n' result += ' set( "{0}", {1} )'.format(name, arg) result += ' );\n' if has_output: result += '\n' result += ' return( {0} );\n'.format(required_output[0]) result += '}' return result
def generate_operation(operation_name, declaration_only=False): intro = Introspect.get(operation_name) required_output = [ name for name in intro.required_output if name != intro.member_x ] has_input = len(intro.method_args) >= 1 has_output = len(required_output) >= 1 has_optional_options = len(intro.optional_input) + len( intro.optional_output) >= 1 # Add a C++ style comment block with some additional markings (@param, # @return) if declaration_only: result = f'\n/**\n * {intro.description.capitalize()}.' for name in intro.method_args: result += f"\n * @param {cppize(name)} {intro.details[name]['blurb']}." if has_output: # skip the first element for name in required_output[1:]: result += f"\n * @param {cppize(name)} {intro.details[name]['blurb']}." if has_optional_options: result += '\n * @param js_options Optional options.' if has_output: result += f"\n * @return {intro.details[required_output[0]]['blurb']}." result += '\n */\n' else: result = '\n' if intro.member_x is None and declaration_only: result += 'static ' if has_output: # the first output arg will be used as the result cpp_type = get_cpp_type(intro.details[required_output[0]]['type'], False) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}' else: result += 'void ' if not declaration_only: result += 'Image::' cplusplus_operation = operation_name if operation_name in cplusplus_keywords: cplusplus_operation += '_image' result += f'{cplusplus_operation}(' for i, name in enumerate(intro.method_args): details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype, True) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}{cppize(name)}' if i != len(intro.method_args) - 1: result += ', ' # output params are passed by reference if has_output: # skip the first element for i, name in enumerate(required_output[1:]): details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype, False) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}*{cppize(name)}' if i != len(required_output) - 2: result += ', ' if has_optional_options: if has_input or len(required_output) > 1: result += ', ' result += f"emscripten::val js_options{' = emscripten::val::null()' if declaration_only else ''}" result += ')' # if no 'this' available, it's a class method and they are all const if intro.member_x is not None: result += ' const' if declaration_only: result += ';' return result result += '\n{\n' if has_output: # the first output arg will be used as the result name = required_output[0] gtype = intro.details[name]['type'] cpp_type = 'VipsBlob *' if ( gtype == GValue.blob_type) else get_cpp_type(gtype, False) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f' {cpp_type}{spacing}{ cppize(name)};\n\n' separate_blob = False for name in intro.method_args: if intro.details[name]['type'] == GValue.blob_type: # We must take a copy of the data. result += f' VipsBlob *blob = vips_blob_copy({name}.c_str(), {name}.size());\n' separate_blob = True break if not separate_blob: result += f" {'Image::' if intro.member_x is None else 'this->'}" result += f'call("{operation_name}",' result += f"{' nullptr,' if intro.member_x is None else ''}\n" padding = ' ' * 16 if intro.member_x is None else ' ' * 15 if separate_blob: padding += ' ' * 6 result += ' Option *options = (new Option)' else: result += f'{padding}(new Option)' if intro.member_x is not None: result += f'\n {padding}->set("{intro.member_x}", *this)' all_required = intro.method_args if has_output: # first element needs to be passed by reference arg = cppize(required_output[0]) result += f'\n {padding}->set("{required_output[0]}", &{arg})' # append the remaining list all_required += required_output[1:] for name in all_required: gtype = intro.details[name]['type'] if gtype == GValue.blob_type: arg = 'blob' elif name not in required_output and get_cpp_type( gtype, True) == 'emscripten::val': type = to_snake_case(remove_prefix(type_name(gtype))).upper() arg = f'VIPS_TYPE_{type}, {cppize(name)}' # a match image is needed for image types if intro.member_x is not None \ and (gtype == GValue.image_type or gtype == GValue.array_image_type): arg += ', this' else: arg = cppize(name) result += f'\n {padding}->set("{name}", {arg})' if separate_blob: result += ';\n' result += ' vips_area_unref(VIPS_AREA(blob));\n\n' result += f" {'Image::' if intro.member_x is None else 'this->'}" result += f'call("{operation_name}",' result += f"{' nullptr,' if intro.member_x is None else ''} options, js_options);\n" else: result += f',\n{padding}js_options);\n' if has_optional_options else ');\n' if has_output: gtype = intro.details[required_output[0]]['type'] result += '\n' if gtype == GValue.blob_type: result += ' emscripten::val result = emscripten::val(emscripten::typed_memory_view(\n' result += f' VIPS_AREA({required_output[0]})->length,\n' result += f' reinterpret_cast<uint8_t *>(VIPS_AREA({required_output[0]})->data)));\n' result += f' VIPS_AREA({required_output[0]})->free_fn = nullptr;\n' result += f' vips_area_unref(VIPS_AREA({required_output[0]}));\n\n' result += ' return result;\n' else: result += f' return {required_output[0]};\n' result += '}' return result