123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945 |
- ###############################################################################
- #
- # IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
- #
- # By downloading, copying, installing or using the software you agree to this license.
- # If you do not agree to this license, do not download, install,
- # copy or use the software.
- #
- #
- # License Agreement
- # For Open Source Computer Vision Library
- #
- # Copyright (C) 2013, OpenCV Foundation, all rights reserved.
- # Third party copyrights are property of their respective owners.
- #
- # Redistribution and use in source and binary forms, with or without modification,
- # are permitted provided that the following conditions are met:
- #
- # * Redistribution's of source code must retain the above copyright notice,
- # this list of conditions and the following disclaimer.
- #
- # * Redistribution's in binary form must reproduce the above copyright notice,
- # this list of conditions and the following disclaimer in the documentation
- # and/or other materials provided with the distribution.
- #
- # * The name of the copyright holders may not be used to endorse or promote products
- # derived from this software without specific prior written permission.
- #
- # This software is provided by the copyright holders and contributors "as is" and
- # any express or implied warranties, including, but not limited to, the implied
- # warranties of merchantability and fitness for a particular purpose are disclaimed.
- # In no event shall the Intel Corporation or contributors be liable for any direct,
- # indirect, incidental, special, exemplary, or consequential damages
- # (including, but not limited to, procurement of substitute goods or services;
- # loss of use, data, or profits; or business interruption) however caused
- # and on any theory of liability, whether in contract, strict liability,
- # or tort (including negligence or otherwise) arising in any way out of
- # the use of this software, even if advised of the possibility of such damage.
- #
- ###############################################################################
- # AUTHOR: Sajjad Taheri, University of California, Irvine. sajjadt[at]uci[dot]edu
- #
- # LICENSE AGREEMENT
- # Copyright (c) 2015, 2015 The Regents of the University of California (Regents)
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are met:
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- # 3. Neither the name of the University nor the
- # names of its contributors may be used to endorse or promote products
- # derived from this software without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' AND ANY
- # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- # DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
- # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ###############################################################################
- from __future__ import print_function
- import sys, re, os
- from templates import *
- if sys.version_info[0] >= 3:
- from io import StringIO
- else:
- from cStringIO import StringIO
- func_table = {}
- # Ignore these functions due to Embind limitations for now
- ignore_list = ['locate', #int&
- 'minEnclosingCircle', #float&
- 'checkRange',
- 'minMaxLoc', #double*
- 'floodFill', # special case, implemented in core_bindings.cpp
- 'phaseCorrelate',
- 'randShuffle',
- 'calibrationMatrixValues', #double&
- 'undistortPoints', # global redefinition
- 'CamShift', #Rect&
- 'meanShift' #Rect&
- ]
- def makeWhiteList(module_list):
- wl = {}
- for m in module_list:
- for k in m.keys():
- if k in wl:
- wl[k] += m[k]
- else:
- wl[k] = m[k]
- return wl
- white_list = None
- namespace_prefix_override = {
- 'dnn' : '',
- 'aruco' : '',
- }
- # Features to be exported
- export_enums = False
- export_consts = True
- with_wrapped_functions = True
- with_default_params = True
- with_vec_from_js_array = True
- wrapper_namespace = "Wrappers"
- type_dict = {
- 'InputArray': 'const cv::Mat&',
- 'OutputArray': 'cv::Mat&',
- 'InputOutputArray': 'cv::Mat&',
- 'InputArrayOfArrays': 'const std::vector<cv::Mat>&',
- 'OutputArrayOfArrays': 'std::vector<cv::Mat>&',
- 'string': 'std::string',
- 'String': 'std::string',
- 'const String&':'const std::string&'
- }
- def normalize_class_name(name):
- return re.sub(r"^cv\.", "", name).replace(".", "_")
- class ClassProp(object):
- def __init__(self, decl):
- self.tp = decl[0].replace("*", "_ptr").strip()
- self.name = decl[1]
- self.readonly = True
- if "/RW" in decl[3]:
- self.readonly = False
- class ClassInfo(object):
- def __init__(self, name, decl=None):
- self.cname = name.replace(".", "::")
- self.name = self.wname = normalize_class_name(name)
- self.ismap = False
- self.issimple = False
- self.isalgorithm = False
- self.methods = {}
- self.ext_constructors = {}
- self.props = []
- self.consts = {}
- customname = False
- self.jsfuncs = {}
- self.constructor_arg_num = set()
- self.has_smart_ptr = False
- if decl:
- self.bases = decl[1].split()[1:]
- if len(self.bases) > 1:
- self.bases = [self.bases[0].strip(",")]
- # return sys.exit(-1)
- if self.bases and self.bases[0].startswith("cv::"):
- self.bases[0] = self.bases[0][4:]
- if self.bases and self.bases[0] == "Algorithm":
- self.isalgorithm = True
- for m in decl[2]:
- if m.startswith("="):
- self.wname = m[1:]
- customname = True
- elif m == "/Map":
- self.ismap = True
- elif m == "/Simple":
- self.issimple = True
- self.props = [ClassProp(p) for p in decl[3]]
- if not customname and self.wname.startswith("Cv"):
- self.wname = self.wname[2:]
- def handle_ptr(tp):
- if tp.startswith('Ptr_'):
- tp = 'Ptr<' + "::".join(tp.split('_')[1:]) + '>'
- return tp
- def handle_vector(tp):
- if tp.startswith('vector_'):
- tp = handle_vector(tp[tp.find('_') + 1:])
- tp = 'std::vector<' + "::".join(tp.split('_')) + '>'
- return tp
- class ArgInfo(object):
- def __init__(self, arg_tuple):
- self.tp = handle_ptr(arg_tuple[0]).strip()
- self.name = arg_tuple[1]
- self.defval = arg_tuple[2]
- self.isarray = False
- self.arraylen = 0
- self.arraycvt = None
- self.inputarg = True
- self.outputarg = False
- self.returnarg = False
- self.const = False
- self.reference = False
- for m in arg_tuple[3]:
- if m == "/O":
- self.inputarg = False
- self.outputarg = True
- self.returnarg = True
- elif m == "/IO":
- self.inputarg = True
- self.outputarg = True
- self.returnarg = True
- elif m.startswith("/A"):
- self.isarray = True
- self.arraylen = m[2:].strip()
- elif m.startswith("/CA"):
- self.isarray = True
- self.arraycvt = m[2:].strip()
- elif m == "/C":
- self.const = True
- elif m == "/Ref":
- self.reference = True
- if self.tp == "Mat":
- if self.outputarg:
- self.tp = "cv::Mat&"
- elif self.inputarg:
- self.tp = "const cv::Mat&"
- if self.tp == "vector_Mat":
- if self.outputarg:
- self.tp = "std::vector<cv::Mat>&"
- elif self.inputarg:
- self.tp = "const std::vector<cv::Mat>&"
- self.tp = handle_vector(self.tp).strip()
- if self.const:
- self.tp = "const " + self.tp
- if self.reference:
- self.tp = self.tp + "&"
- self.py_inputarg = False
- self.py_outputarg = False
- class FuncVariant(object):
- def __init__(self, class_name, name, decl, is_constructor, is_class_method, is_const, is_virtual, is_pure_virtual, ref_return, const_return):
- self.class_name = class_name
- self.name = self.wname = name
- self.is_constructor = is_constructor
- self.is_class_method = is_class_method
- self.is_const = is_const
- self.is_virtual = is_virtual
- self.is_pure_virtual = is_pure_virtual
- self.refret = ref_return
- self.constret = const_return
- self.rettype = handle_vector(handle_ptr(decl[1]).strip()).strip()
- if self.rettype == "void":
- self.rettype = ""
- self.args = []
- self.array_counters = {}
- for a in decl[3]:
- ainfo = ArgInfo(a)
- if ainfo.isarray and not ainfo.arraycvt:
- c = ainfo.arraylen
- c_arrlist = self.array_counters.get(c, [])
- if c_arrlist:
- c_arrlist.append(ainfo.name)
- else:
- self.array_counters[c] = [ainfo.name]
- self.args.append(ainfo)
- class FuncInfo(object):
- def __init__(self, class_name, name, cname, namespace, isconstructor):
- self.name_id = '_'.join([namespace] + ([class_name] if class_name else []) + [name]) # unique id for dict key
- self.class_name = class_name
- self.name = name
- self.cname = cname
- self.namespace = namespace
- self.variants = []
- self.is_constructor = isconstructor
- def add_variant(self, variant):
- self.variants.append(variant)
- class Namespace(object):
- def __init__(self):
- self.funcs = {}
- self.enums = {}
- self.consts = {}
- class JSWrapperGenerator(object):
- def __init__(self):
- self.bindings = []
- self.wrapper_funcs = []
- self.classes = {} # FIXIT 'classes' should belong to 'namespaces'
- self.namespaces = {}
- self.enums = {} # FIXIT 'enums' should belong to 'namespaces'
- self.parser = hdr_parser.CppHeaderParser()
- self.class_idx = 0
- def add_class(self, stype, name, decl):
- class_info = ClassInfo(name, decl)
- class_info.decl_idx = self.class_idx
- self.class_idx += 1
- if class_info.name in self.classes:
- print("Generator error: class %s (cpp_name=%s) already exists" \
- % (class_info.name, class_info.cname))
- sys.exit(-1)
- self.classes[class_info.name] = class_info
- if class_info.bases:
- chunks = class_info.bases[0].split('::')
- base = '_'.join(chunks)
- while base not in self.classes and len(chunks) > 1:
- del chunks[-2]
- base = '_'.join(chunks)
- if base not in self.classes:
- print("Generator error: unable to resolve base %s for %s"
- % (class_info.bases[0], class_info.name))
- sys.exit(-1)
- else:
- class_info.bases[0] = "::".join(chunks)
- class_info.isalgorithm |= self.classes[base].isalgorithm
- def split_decl_name(self, name):
- chunks = name.split('.')
- namespace = chunks[:-1]
- classes = []
- while namespace and '.'.join(namespace) not in self.parser.namespaces:
- classes.insert(0, namespace.pop())
- return namespace, classes, chunks[-1]
- def add_enum(self, decl):
- name = decl[0].rsplit(" ", 1)[1]
- namespace, classes, val = self.split_decl_name(name)
- namespace = '.'.join(namespace)
- ns = self.namespaces.setdefault(namespace, Namespace())
- if len(name) == 0: name = "<unnamed>"
- if name.endswith("<unnamed>"):
- i = 0
- while True:
- i += 1
- candidate_name = name.replace("<unnamed>", "unnamed_%u" % i)
- if candidate_name not in ns.enums:
- name = candidate_name
- break;
- cname = name.replace('.', '::')
- type_dict[normalize_class_name(name)] = cname
- if name in ns.enums:
- print("Generator warning: enum %s (cname=%s) already exists" \
- % (name, cname))
- # sys.exit(-1)
- else:
- ns.enums[name] = []
- for item in decl[3]:
- ns.enums[name].append(item)
- const_decls = decl[3]
- for decl in const_decls:
- name = decl[0]
- self.add_const(name.replace("const ", "").strip(), decl)
- def add_const(self, name, decl):
- cname = name.replace('.','::')
- namespace, classes, name = self.split_decl_name(name)
- namespace = '.'.join(namespace)
- name = '_'.join(classes+[name])
- ns = self.namespaces.setdefault(namespace, Namespace())
- if name in ns.consts:
- print("Generator error: constant %s (cname=%s) already exists" \
- % (name, cname))
- sys.exit(-1)
- ns.consts[name] = cname
- def add_func(self, decl):
- namespace, classes, barename = self.split_decl_name(decl[0])
- cpp_name = "::".join(namespace + classes + [barename])
- name = barename
- class_name = ''
- bare_class_name = ''
- if classes:
- class_name = normalize_class_name('.'.join(namespace + classes))
- bare_class_name = classes[-1]
- namespace = '.'.join(namespace)
- is_constructor = name == bare_class_name
- is_class_method = False
- is_const_method = False
- is_virtual_method = False
- is_pure_virtual_method = False
- const_return = False
- ref_return = False
- for m in decl[2]:
- if m == "/S":
- is_class_method = True
- elif m == "/C":
- is_const_method = True
- elif m == "/V":
- is_virtual_method = True
- elif m == "/PV":
- is_pure_virtual_method = True
- elif m == "/Ref":
- ref_return = True
- elif m == "/CRet":
- const_return = True
- elif m.startswith("="):
- name = m[1:]
- if class_name:
- cpp_name = barename
- func_map = self.classes[class_name].methods
- else:
- func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
- fi = FuncInfo(class_name, name, cpp_name, namespace, is_constructor)
- func = func_map.setdefault(fi.name_id, fi)
- variant = FuncVariant(class_name, name, decl, is_constructor, is_class_method, is_const_method,
- is_virtual_method, is_pure_virtual_method, ref_return, const_return)
- func.add_variant(variant)
- def save(self, path, name, buf):
- f = open(path + "/" + name, "wt")
- f.write(buf.getvalue())
- f.close()
- def gen_function_binding_with_wrapper(self, func, ns_name, class_info):
- binding_text = None
- wrapper_func_text = None
- bindings = []
- wrappers = []
- for index, variant in enumerate(func.variants):
- factory = False
- if class_info and 'Ptr<' in variant.rettype:
- factory = True
- base_class_name = variant.rettype
- base_class_name = base_class_name.replace("Ptr<","").replace(">","").strip()
- if base_class_name in self.classes:
- self.classes[base_class_name].has_smart_ptr = True
- else:
- print(base_class_name, ' not found in classes for registering smart pointer using ', class_info.name, 'instead')
- self.classes[class_info.name].has_smart_ptr = True
- def_args = []
- has_def_param = False
- # Return type
- ret_type = 'void' if variant.rettype.strip() == '' else variant.rettype
- if ret_type.startswith('Ptr'): #smart pointer
- ptr_type = ret_type.replace('Ptr<', '').replace('>', '')
- if ptr_type in type_dict:
- ret_type = type_dict[ptr_type]
- for key in type_dict:
- if key in ret_type:
- ret_type = re.sub('(^|[^\w])' + key + '($|[^\w])', type_dict[key], ret_type)
- arg_types = []
- unwrapped_arg_types = []
- for arg in variant.args:
- arg_type = None
- if arg.tp in type_dict:
- arg_type = type_dict[arg.tp]
- else:
- arg_type = arg.tp
- # Add default value
- if with_default_params and arg.defval != '':
- def_args.append(arg.defval);
- arg_types.append(arg_type)
- unwrapped_arg_types.append(arg_type)
- # Function attribute
- func_attribs = ''
- if '*' in ''.join(arg_types):
- func_attribs += ', allow_raw_pointers()'
- if variant.is_pure_virtual:
- func_attribs += ', pure_virtual()'
- # Wrapper function
- if ns_name != None and ns_name != "cv":
- ns_parts = ns_name.split(".")
- if ns_parts[0] == "cv":
- ns_parts = ns_parts[1:]
- ns_part = "_".join(ns_parts) + "_"
- ns_id = '_'.join(ns_parts)
- ns_prefix = namespace_prefix_override.get(ns_id, ns_id)
- if ns_prefix:
- ns_prefix = ns_prefix + '_'
- else:
- ns_prefix = ''
- if class_info == None:
- js_func_name = ns_prefix + func.name
- wrap_func_name = js_func_name + "_wrapper"
- else:
- wrap_func_name = ns_prefix + func.class_name + "_" + func.name + "_wrapper"
- js_func_name = func.name
- # TODO: Name functions based wrap directives or based on arguments list
- if index > 0:
- wrap_func_name += str(index)
- js_func_name += str(index)
- c_func_name = 'Wrappers::' + wrap_func_name
- # Binding template-
- raw_arg_names = ['arg' + str(i + 1) for i in range(0, len(variant.args))]
- arg_names = []
- w_signature = []
- casted_arg_types = []
- for arg_type, arg_name in zip(arg_types, raw_arg_names):
- casted_arg_name = arg_name
- if with_vec_from_js_array:
- # Only support const vector reference as input parameter
- match = re.search(r'const std::vector<(.*)>&', arg_type)
- if match:
- type_in_vect = match.group(1)
- if type_in_vect in ['int', 'float', 'double', 'char', 'uchar', 'String', 'std::string']:
- casted_arg_name = 'emscripten::vecFromJSArray<' + type_in_vect + '>(' + arg_name + ')'
- arg_type = re.sub(r'std::vector<(.*)>', 'emscripten::val', arg_type)
- w_signature.append(arg_type + ' ' + arg_name)
- arg_names.append(casted_arg_name)
- casted_arg_types.append(arg_type)
- arg_types = casted_arg_types
- # Argument list, signature
- arg_names_casted = [c if a == b else c + '.as<' + a + '>()' for a, b, c in
- zip(unwrapped_arg_types, arg_types, arg_names)]
- # Add self object to the parameters
- if class_info and not factory:
- arg_types = [class_info.cname + '&'] + arg_types
- w_signature = [class_info.cname + '& arg0 '] + w_signature
- for j in range(0, len(def_args) + 1):
- postfix = ''
- if j > 0:
- postfix = '_' + str(j);
- ###################################
- # Wrapper
- if factory: # TODO or static
- name = class_info.cname+'::' if variant.class_name else ""
- cpp_call_text = static_class_call_template.substitute(scope=name,
- func=func.cname,
- args=', '.join(arg_names[:len(arg_names)-j]))
- elif class_info:
- cpp_call_text = class_call_template.substitute(obj='arg0',
- func=func.cname,
- args=', '.join(arg_names[:len(arg_names)-j]))
- else:
- cpp_call_text = call_template.substitute(func=func.cname,
- args=', '.join(arg_names[:len(arg_names)-j]))
- wrapper_func_text = wrapper_function_template.substitute(ret_val=ret_type,
- func=wrap_func_name+postfix,
- signature=', '.join(w_signature[:len(w_signature)-j]),
- cpp_call=cpp_call_text,
- const='' if variant.is_const else '')
- ###################################
- # Binding
- if class_info:
- if factory:
- # print("Factory Function: ", c_func_name, len(variant.args) - j, class_info.name)
- if variant.is_pure_virtual:
- # FIXME: workaround for pure virtual in constructor
- # e.g. DescriptorMatcher_clone_wrapper
- continue
- # consider the default parameter variants
- args_num = len(variant.args) - j
- if args_num in class_info.constructor_arg_num:
- # FIXME: workaround for constructor overload with same args number
- # e.g. DescriptorMatcher
- continue
- class_info.constructor_arg_num.add(args_num)
- binding_text = ctr_template.substitute(const='const' if variant.is_const else '',
- cpp_name=c_func_name+postfix,
- ret=ret_type,
- args=','.join(arg_types[:len(arg_types)-j]),
- optional=func_attribs)
- else:
- binding_template = overload_class_static_function_template if variant.is_class_method else \
- overload_class_function_template
- binding_text = binding_template.substitute(js_name=js_func_name,
- const='' if variant.is_const else '',
- cpp_name=c_func_name+postfix,
- ret=ret_type,
- args=','.join(arg_types[:len(arg_types)-j]),
- optional=func_attribs)
- else:
- binding_text = overload_function_template.substitute(js_name=js_func_name,
- cpp_name=c_func_name+postfix,
- const='const' if variant.is_const else '',
- ret=ret_type,
- args=', '.join(arg_types[:len(arg_types)-j]),
- optional=func_attribs)
- bindings.append(binding_text)
- wrappers.append(wrapper_func_text)
- return [bindings, wrappers]
- def gen_function_binding(self, func, class_info):
- if not class_info == None :
- func_name = class_info.cname+'::'+func.cname
- else :
- func_name = func.cname
- binding_text = None
- binding_text_list = []
- for index, variant in enumerate(func.variants):
- factory = False
- #TODO if variant.is_class_method and variant.rettype == ('Ptr<' + class_info.name + '>'):
- if (not class_info == None) and variant.rettype == ('Ptr<' + class_info.name + '>') or (func.name.startswith("create") and variant.rettype):
- factory = True
- base_class_name = variant.rettype
- base_class_name = base_class_name.replace("Ptr<","").replace(">","").strip()
- if base_class_name in self.classes:
- self.classes[base_class_name].has_smart_ptr = True
- else:
- print(base_class_name, ' not found in classes for registering smart pointer using ', class_info.name, 'instead')
- self.classes[class_info.name].has_smart_ptr = True
- # Return type
- ret_type = 'void' if variant.rettype.strip() == '' else variant.rettype
- ret_type = ret_type.strip()
- if ret_type.startswith('Ptr'): #smart pointer
- ptr_type = ret_type.replace('Ptr<', '').replace('>', '')
- if ptr_type in type_dict:
- ret_type = type_dict[ptr_type]
- for key in type_dict:
- if key in ret_type:
- # Replace types. Instead of ret_type.replace we use regular
- # expression to exclude false matches.
- # See https://github.com/opencv/opencv/issues/15514
- ret_type = re.sub('(^|[^\w])' + key + '($|[^\w])', type_dict[key], ret_type)
- if variant.constret and ret_type.startswith('const') == False:
- ret_type = 'const ' + ret_type
- if variant.refret and ret_type.endswith('&') == False:
- ret_type += '&'
- arg_types = []
- orig_arg_types = []
- def_args = []
- for arg in variant.args:
- if arg.tp in type_dict:
- arg_type = type_dict[arg.tp]
- else:
- arg_type = arg.tp
- #if arg.outputarg:
- # arg_type += '&'
- orig_arg_types.append(arg_type)
- if with_default_params and arg.defval != '':
- def_args.append(arg.defval)
- arg_types.append(orig_arg_types[-1])
- # Function attribute
- func_attribs = ''
- if '*' in ''.join(orig_arg_types):
- func_attribs += ', allow_raw_pointers()'
- if variant.is_pure_virtual:
- func_attribs += ', pure_virtual()'
- #TODO better naming
- #if variant.name in self.jsfunctions:
- #else
- js_func_name = variant.name
- c_func_name = func.cname if (factory and variant.is_class_method == False) else func_name
- ################################### Binding
- for j in range(0, len(def_args) + 1):
- postfix = ''
- if j > 0:
- postfix = '_' + str(j);
- if factory:
- binding_text = ctr_template.substitute(const='const' if variant.is_const else '',
- cpp_name=c_func_name+postfix,
- ret=ret_type,
- args=','.join(arg_types[:len(arg_types)-j]),
- optional=func_attribs)
- else:
- binding_template = overload_class_static_function_template if variant.is_class_method else \
- overload_function_template if class_info == None else overload_class_function_template
- binding_text = binding_template.substitute(js_name=js_func_name,
- const='const' if variant.is_const else '',
- cpp_name=c_func_name+postfix,
- ret=ret_type,
- args=','.join(arg_types[:len(arg_types)-1]),
- optional=func_attribs)
- binding_text_list.append(binding_text)
- return binding_text_list
- def print_decls(self, decls):
- """
- Prints the list of declarations, retrieived by the parse() method
- """
- for d in decls:
- print(d[0], d[1], ";".join(d[2]))
- for a in d[3]:
- print(" ", a[0], a[1], a[2], end="")
- if a[3]:
- print("; ".join(a[3]))
- else:
- print()
- def gen(self, dst_file, src_files, core_bindings):
- # step 1: scan the headers and extract classes, enums and functions
- headers = []
- for hdr in src_files:
- decls = self.parser.parse(hdr)
- # print(hdr);
- # self.print_decls(decls);
- if len(decls) == 0:
- continue
- headers.append(hdr[hdr.rindex('opencv2/'):])
- for decl in decls:
- name = decl[0]
- type = name[:name.find(" ")]
- if type == "struct" or type == "class": # class/structure case
- name = name[name.find(" ") + 1:].strip()
- self.add_class(type, name, decl)
- elif name.startswith("enum"): # enumerations
- self.add_enum(decl)
- elif name.startswith("const"):
- # constant
- self.add_const(name.replace("const ", "").strip(), decl)
- else: # class/global function
- self.add_func(decl)
- # step 2: generate bindings
- # Global functions
- for ns_name, ns in sorted(self.namespaces.items()):
- ns_parts = ns_name.split('.')
- if ns_parts[0] != 'cv':
- print('Ignore namespace: {}'.format(ns_name))
- continue
- else:
- ns_parts = ns_parts[1:]
- ns_id = '_'.join(ns_parts)
- ns_prefix = namespace_prefix_override.get(ns_id, ns_id)
- for name_id, func in sorted(ns.funcs.items()):
- name = func.name
- if ns_prefix:
- name = ns_prefix + '_' + name
- if name in ignore_list:
- continue
- if not name in white_list['']:
- #print('Not in whitelist: "{}" from ns={}'.format(name, ns_name))
- continue
- ext_cnst = False
- # Check if the method is an external constructor
- for variant in func.variants:
- if "Ptr<" in variant.rettype:
- # Register the smart pointer
- base_class_name = variant.rettype
- base_class_name = base_class_name.replace("Ptr<","").replace(">","").strip()
- self.classes[base_class_name].has_smart_ptr = True
- # Adds the external constructor
- class_name = func.name.replace("create", "")
- if not class_name in self.classes:
- self.classes[base_class_name].methods[func.cname] = func
- else:
- self.classes[class_name].methods[func.cname] = func
- ext_cnst = True
- if ext_cnst:
- continue
- if with_wrapped_functions:
- binding, wrapper = self.gen_function_binding_with_wrapper(func, ns_name, class_info=None)
- self.bindings += binding
- self.wrapper_funcs += wrapper
- else:
- binding = self.gen_function_binding(func, class_info=None)
- self.bindings+=binding
- # generate code for the classes and their methods
- for name, class_info in sorted(self.classes.items()):
- class_bindings = []
- if not name in white_list:
- continue
- # Generate bindings for methods
- for method_name, method in sorted(class_info.methods.items()):
- if method.cname in ignore_list:
- continue
- if not method.name in white_list[method.class_name]:
- continue
- if method.is_constructor:
- for variant in method.variants:
- args = []
- for arg in variant.args:
- arg_type = type_dict[arg.tp] if arg.tp in type_dict else arg.tp
- args.append(arg_type)
- # print('Constructor: ', class_info.name, len(variant.args))
- args_num = len(variant.args)
- if args_num in class_info.constructor_arg_num:
- continue
- class_info.constructor_arg_num.add(args_num)
- class_bindings.append(constructor_template.substitute(signature=', '.join(args)))
- else:
- if with_wrapped_functions and (len(method.variants) > 1 or len(method.variants[0].args)>0 or "String" in method.variants[0].rettype):
- binding, wrapper = self.gen_function_binding_with_wrapper(method, None, class_info=class_info)
- self.wrapper_funcs = self.wrapper_funcs + wrapper
- class_bindings = class_bindings + binding
- else:
- binding = self.gen_function_binding(method, class_info=class_info)
- class_bindings = class_bindings + binding
- # Regiseter Smart pointer
- if class_info.has_smart_ptr:
- class_bindings.append(smart_ptr_reg_template.substitute(cname=class_info.cname, name=class_info.name))
- # Attach external constructors
- # for method_name, method in class_info.ext_constructors.items():
- # print("ext constructor", method_name)
- #if class_info.ext_constructors:
- # Generate bindings for properties
- for property in class_info.props:
- _class_property = class_property_enum_template if property.tp in type_dict else class_property_template
- class_bindings.append(_class_property.substitute(js_name=property.name, cpp_name='::'.join(
- [class_info.cname, property.name])))
- dv = ''
- base = Template("""base<$base>""")
- assert len(class_info.bases) <= 1 , "multiple inheritance not supported"
- if len(class_info.bases) == 1:
- dv = "," + base.substitute(base=', '.join(class_info.bases))
- self.bindings.append(class_template.substitute(cpp_name=class_info.cname,
- js_name=name,
- class_templates=''.join(class_bindings),
- derivation=dv))
- if export_enums:
- # step 4: generate bindings for enums
- # TODO anonymous enums are ignored for now.
- for ns_name, ns in sorted(self.namespaces.items()):
- if ns_name.split('.')[0] != 'cv':
- continue
- for name, enum in sorted(ns.enums.items()):
- if not name.endswith('.anonymous'):
- name = name.replace("cv.", "")
- enum_values = []
- for enum_val in enum:
- value = enum_val[0][enum_val[0].rfind(".")+1:]
- enum_values.append(enum_item_template.substitute(val=value,
- cpp_val=name.replace('.', '::')+'::'+value))
- self.bindings.append(enum_template.substitute(cpp_name=name.replace(".", "::"),
- js_name=name.replace(".", "_"),
- enum_items=''.join(enum_values)))
- else:
- print(name)
- #TODO: represent anonymous enums with constants
- if export_consts:
- # step 5: generate bindings for consts
- for ns_name, ns in sorted(self.namespaces.items()):
- if ns_name.split('.')[0] != 'cv':
- continue
- for name, const in sorted(ns.consts.items()):
- # print("Gen consts: ", name, const)
- self.bindings.append(const_template.substitute(js_name=name, value=const))
- with open(core_bindings) as f:
- ret = f.read()
- header_includes = '\n'.join(['#include "{}"'.format(hdr) for hdr in headers])
- ret = ret.replace('@INCLUDES@', header_includes)
- defis = '\n'.join(self.wrapper_funcs)
- ret += wrapper_codes_template.substitute(ns=wrapper_namespace, defs=defis)
- ret += emscripten_binding_template.substitute(binding_name='testBinding', bindings=''.join(self.bindings))
- # print(ret)
- text_file = open(dst_file, "w")
- text_file.write(ret)
- text_file.close()
- if __name__ == "__main__":
- if len(sys.argv) < 5:
- print("Usage:\n", \
- os.path.basename(sys.argv[0]), \
- "<full path to hdr_parser.py> <bindings.cpp> <headers.txt> <core_bindings.cpp> <opencv_js.config.py>")
- print("Current args are: ", ", ".join(["'"+a+"'" for a in sys.argv]))
- exit(0)
- dstdir = "."
- hdr_parser_path = os.path.abspath(sys.argv[1])
- if hdr_parser_path.endswith(".py"):
- hdr_parser_path = os.path.dirname(hdr_parser_path)
- sys.path.append(hdr_parser_path)
- import hdr_parser
- bindingsCpp = sys.argv[2]
- headers = open(sys.argv[3], 'r').read().split(';')
- coreBindings = sys.argv[4]
- whiteListFile = sys.argv[5]
- exec(open(whiteListFile).read())
- assert(white_list)
- generator = JSWrapperGenerator()
- generator.gen(bindingsCpp, headers, coreBindings)
|