gen_java.py 44.4 KB
Newer Older
A
Andrey Kamaev 已提交
1 2 3 4 5 6 7 8
import sys, re, os.path
from string import Template

try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
class_ignore_list = (
    #core
    "FileNode",
    "FileStorage",
    #highgui
    "VideoWriter",
    "VideoCapture",
)

func_ignore_list = (
    #core
    "checkHardwareSupport",
    "setUseOptimized",
    "useOptimized",
    "vconcat",
    #highgui
    "namedWindow",
    "destroyWindow",
    "destroyAllWindows",
    "startWindowThread",
    "setWindowProperty",
    "getWindowProperty",
    "getTrackbarPos",
    "setTrackbarPos",
    "imshow",
    "waitKey",
)

37
const_ignore_list = (
L
Changed  
Leonid Beynenson 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
    "CV_CAP_OPENNI",
    "CV_CAP_PROP_OPENNI_",
    "WINDOW_AUTOSIZE",
    "CV_WND_PROP_",
    "CV_WINDOW_",
    "CV_EVENT_",
    "CV_GUI_",
    "CV_PUSH_BUTTON",
    "CV_CHECKBOX",
    "CV_RADIOBOX",

    #attention! the following constants are added to this list using code automatic generation -- should be checked
    "CV_CAP_ANY",
    "CV_CAP_MIL",
    "CV_CAP_VFW",
    "CV_CAP_V4L",
    "CV_CAP_V4L2",
    "CV_CAP_FIREWARE",
    "CV_CAP_FIREWIRE",
    "CV_CAP_IEEE1394",
    "CV_CAP_DC1394",
    "CV_CAP_CMU1394",
    "CV_CAP_STEREO",
    "CV_CAP_TYZX",
    "CV_TYZX_LEFT",
    "CV_TYZX_RIGHT",
    "CV_TYZX_COLOR",
    "CV_TYZX_Z",
    "CV_CAP_QT",
    "CV_CAP_UNICAP",
    "CV_CAP_DSHOW",
    "CV_CAP_PVAPI",
    "CV_CAP_PROP_DC1394_OFF",
    "CV_CAP_PROP_DC1394_MODE_MANUAL",
    "CV_CAP_PROP_DC1394_MODE_AUTO",
    "CV_CAP_PROP_DC1394_MODE_ONE_PUSH_AUTO",
    "CV_CAP_PROP_POS_MSEC",
    "CV_CAP_PROP_POS_FRAMES",
    "CV_CAP_PROP_POS_AVI_RATIO",
    "CV_CAP_PROP_FPS",
    "CV_CAP_PROP_FOURCC",
    "CV_CAP_PROP_FRAME_COUNT",
    "CV_CAP_PROP_FORMAT",
    "CV_CAP_PROP_MODE",
    "CV_CAP_PROP_BRIGHTNESS",
    "CV_CAP_PROP_CONTRAST",
    "CV_CAP_PROP_SATURATION",
    "CV_CAP_PROP_HUE",
    "CV_CAP_PROP_GAIN",
    "CV_CAP_PROP_EXPOSURE",
    "CV_CAP_PROP_CONVERT_RGB",
    "CV_CAP_PROP_WHITE_BALANCE_BLUE_U",
    "CV_CAP_PROP_RECTIFICATION",
    "CV_CAP_PROP_MONOCROME",
    "CV_CAP_PROP_SHARPNESS",
    "CV_CAP_PROP_AUTO_EXPOSURE",
    "CV_CAP_PROP_GAMMA",
    "CV_CAP_PROP_TEMPERATURE",
    "CV_CAP_PROP_TRIGGER",
    "CV_CAP_PROP_TRIGGER_DELAY",
    "CV_CAP_PROP_WHITE_BALANCE_RED_V",
    "CV_CAP_PROP_MAX_DC1394",
    "CV_CAP_GSTREAMER_QUEUE_LENGTH",
    "CV_CAP_PROP_PVAPI_MULTICASTIP",
102 103 104 105 106 107 108 109
    "CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING",
    "EVENT_.*",
    "CV_L?(BGRA?|RGBA?|GRAY|XYZ|YCrCb|Luv|Lab|HLS|YUV|HSV)\d*2L?(BGRA?|RGBA?|GRAY|XYZ|YCrCb|Luv|Lab|HLS|YUV|HSV).*",
    "CV_COLORCVT_MAX",
    "CV_.*Bayer.*",
    "CV_YUV420i2.+",
    "CV_TM_.+",
    "CV_FLOODFILL_.+",
110 111
)

112

113 114 115 116 117 118 119 120
# c_type    : { java/jni correspondence }
type_dict = {
# "simple"  : { j_type : "?", jn_type : "?", jni_type : "?", suffix : "?" },
    ""        : { "j_type" : "", "jn_type" : "long", "jni_type" : "jlong" }, # c-tor ret_type
    "void"    : { "j_type" : "void", "jn_type" : "void", "jni_type" : "void" },
    "env"     : { "j_type" : "", "jn_type" : "", "jni_type" : "JNIEnv*"},
    "cls"     : { "j_type" : "", "jn_type" : "", "jni_type" : "jclass"},
    "bool"    : { "j_type" : "boolean", "jn_type" : "boolean", "jni_type" : "jboolean", "suffix" : "Z" },
121 122
    "int"     : { "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" },
    "long"    : { "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" },
123 124 125 126
    "float"   : { "j_type" : "float", "jn_type" : "float", "jni_type" : "jfloat", "suffix" : "F" },
    "double"  : { "j_type" : "double", "jn_type" : "double", "jni_type" : "jdouble", "suffix" : "D" },
    "size_t"  : { "j_type" : "long", "jn_type" : "long", "jni_type" : "jlong", "suffix" : "J" },
    "__int64" : { "j_type" : "long", "jn_type" : "long", "jni_type" : "jlong", "suffix" : "J" },
127
    "int64"   : { "j_type" : "long", "jn_type" : "long", "jni_type" : "jlong", "suffix" : "J" },
128
    "double[]": { "j_type" : "double[]", "jn_type" : "double[]", "jni_type" : "jdoubleArray", "suffix" : "_3D" },
129 130 131 132 133 134 135 136
    "vector_Point": { "j_type" : "java.util.List<Point>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<Point> %(n)s", "suffix" : "J" },
    "vector_Mat" :  { "j_type" : "java.util.List<Mat>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<Mat> %(n)s", "suffix" : "J" },
    "vector_KeyPoint" : { "j_type" : "java.util.List<KeyPoint>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<KeyPoint> %(n)s", "suffix" : "J" },
    "vector_Rect" : { "j_type" : "java.util.List<Rect>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<Rect> %(n)s", "suffix" : "J" },
    "vector_uchar" : { "j_type" : "java.util.List<Byte>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<uchar> %(n)s", "suffix" : "J" },
    "vector_int" : { "j_type" : "java.util.List<Integer>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<int> %(n)s", "suffix" : "J" },
    "vector_float" : { "j_type" : "java.util.List<Float>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<float> %(n)s", "suffix" : "J" },
    "vector_double" : { "j_type" : "java.util.List<Double>", "jn_type" : "long", "jni_type" : "jlong", "jni_var" : "vector<double> %(n)s", "suffix" : "J" },
137 138
# "complex" : { j_type : "?", jn_args : (("", ""),), jn_name : "", jni_var : "", jni_name : "", "suffix" : "?" },
    "Mat"     : { "j_type" : "Mat", "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
139
                  "jni_var" : "Mat& %(n)s = *((Mat*)%(n)s_nativeObj)",
140
                  "jni_type" : "jlong", #"jni_name" : "*%(n)s",
141 142
                  "suffix" : "J" },
    "Point"   : { "j_type" : "Point", "jn_args" : (("double", ".x"), ("double", ".y")),
143
                  "jni_var" : "Point %(n)s((int)%(n)s_x, (int)%(n)s_y)", "jni_type" : "jdoubleArray",
144 145
                  "suffix" : "DD"},
    "Point2f" : { "j_type" : "Point", "jn_args" : (("double", ".x"), ("double", ".y")),
146
                  "jni_var" : "Point2f %(n)s((float)%(n)s_x, (float)%(n)s_y)", "jni_type" : "jdoubleArray",
147 148
                  "suffix" : "DD"},
    "Point2d" : { "j_type" : "Point", "jn_args" : (("double", ".x"), ("double", ".y")),
149
                  "jni_var" : "Point2d %(n)s(%(n)s_x, %(n)s_y)", "jni_type" : "jdoubleArray",
150 151
                  "suffix" : "DD"},
    "Point3i" : { "j_type" : "Point", "jn_args" : (("double", ".x"), ("double", ".y"), ("double", ".z")),
152
                  "jni_var" : "Point3i %(n)s((int)%(n)s_x, (int)%(n)s_y, (int)%(n)s_z)", "jni_type" : "jdoubleArray",
153 154
                  "suffix" : "DDD"},
    "Point3f" : { "j_type" : "Point", "jn_args" : (("double", ".x"), ("double", ".y"), ("double", ".z")),
155
                  "jni_var" : "Point3f %(n)s((float)%(n)s_x, (float)%(n)s_y, (float)%(n)s_z)", "jni_type" : "jdoubleArray",
156 157
                  "suffix" : "DDD"},
    "Point3d" : { "j_type" : "Point", "jn_args" : (("double", ".x"), ("double", ".y"), ("double", ".z")),
158
                  "jni_var" : "Point3d %(n)s(%(n)s_x, %(n)s_y, %(n)s_z)", "jni_type" : "jdoubleArray",
159 160
                  "suffix" : "DDD"},
    "Rect"    : { "j_type" : "Rect",  "jn_args" : (("int", ".x"), ("int", ".y"), ("int", ".width"), ("int", ".height")),
161
                  "jni_var" : "Rect %(n)s(%(n)s_x, %(n)s_y, %(n)s_width, %(n)s_height)", "jni_type" : "jdoubleArray",
162
                  "suffix" : "IIII"},
163
    "Size"    : { "j_type" : "Size",  "jn_args" : (("double", ".width"), ("double", ".height")),
164
                  "jni_var" : "Size %(n)s((int)%(n)s_width, (int)%(n)s_height)", "jni_type" : "jdoubleArray",
165 166
                  "suffix" : "DD"},
    "Size2f"  : { "j_type" : "Size",  "jn_args" : (("double", ".width"), ("double", ".height")),
167
                  "jni_var" : "Size2f %(n)s((float)%(n)s_width, (float)%(n)s_height)", "jni_type" : "jdoubleArray",
168 169
                  "suffix" : "DD"},
 "RotatedRect": { "j_type" : "RotatedRect",  "jn_args" : (("double", ".center.x"), ("double", ".center.y"), ("double", ".size.width"), ("double", ".size.height"), ("double", ".angle")),
170
                  "jni_var" : "RotatedRect %(n)s(cv::Point2f(%(n)s_center_x, %(n)s_center_y), cv::Size2f(%(n)s_size_width, %(n)s_size_height), %(n)s_angle)",
171
                  "jni_type" : "jdoubleArray", "suffix" : "DDDDD"},
172 173
    "Scalar"  : { "j_type" : "Scalar",  "jn_args" : (("double", ".val[0]"), ("double", ".val[1]"), ("double", ".val[2]"), ("double", ".val[3]")),
                  "jni_var" : "Scalar %(n)s(%(n)s_val0, %(n)s_val1, %(n)s_val2, %(n)s_val3)", "jni_type" : "jdoubleArray",
174
                  "suffix" : "DDDD"},
175
    "Range"   : { "j_type" : "Range",  "jn_args" : (("int", ".start"), ("int", ".end")),
176
                  "jni_var" : "Range %(n)s(%(n)s_start, %(n)s_end)", "jni_type" : "jdoubleArray",
177
                  "suffix" : "II"},
L
Leonid Beynenson 已提交
178
    "CvSlice" : { "j_type" : "Range",  "jn_args" : (("int", ".start"), ("int", ".end")),
179
                  "jni_var" : "Range %(n)s(%(n)s_start, %(n)s_end)", "jni_type" : "jdoubleArray",
180
                  "suffix" : "II"},
181 182
    "string"  : { "j_type" : "java.lang.String",  "jn_type" : "java.lang.String",
                  "jni_type" : "jstring", "jni_name" : "n_%(n)s",
183
                  "jni_var" : 'const char* utf_%(n)s = env->GetStringUTFChars(%(n)s, 0); std::string n_%(n)s( utf_%(n)s ? utf_%(n)s : "" ); env->ReleaseStringUTFChars(%(n)s, utf_%(n)s)',
184
                  "suffix" : "Ljava_lang_String_2"},
185 186 187 188
    "String"  : { "j_type" : "java.lang.String",  "jn_type" : "java.lang.String",
                  "jni_type" : "jstring", "jni_name" : "n_%(n)s",
                  "jni_var" : 'const char* utf_%(n)s = env->GetStringUTFChars(%(n)s, 0); String n_%(n)s( utf_%(n)s ? utf_%(n)s : "" ); env->ReleaseStringUTFChars(%(n)s, utf_%(n)s)',
                  "suffix" : "Ljava_lang_String_2"},
189 190 191 192
    "c_string": { "j_type" : "java.lang.String",  "jn_type" : "java.lang.String",
                  "jni_type" : "jstring", "jni_name" : "n_%(n)s.c_str()",
                  "jni_var" : 'const char* utf_%(n)s = env->GetStringUTFChars(%(n)s, 0); std::string n_%(n)s( utf_%(n)s ? utf_%(n)s : "" ); env->ReleaseStringUTFChars(%(n)s, utf_%(n)s)',
                  "suffix" : "Ljava_lang_String_2"},
L
Leonid Beynenson 已提交
193 194 195
"TermCriteria": { "j_type" : "TermCriteria",  "jn_args" : (("int", ".type"), ("int", ".maxCount"), ("double", ".epsilon")),
                  "jni_var" : "TermCriteria %(n)s(%(n)s_type, %(n)s_maxCount, %(n)s_epsilon)",
                  "suffix" : "IID"},
196 197 198 199
    "Vec3d"   : { "j_type" : "double[]",  "jn_args" : (("double", ".val[0]"), ("double", ".val[1]"), ("double", ".val[2]")),
                  "jn_type" : "double[]",
                  "jni_var" : "Vec3d %(n)s(%(n)s_val0, %(n)s_val1, %(n)s_val2)", "jni_type" : "jdoubleArray",
                  "suffix" : "DDD"},
A
Andrey Kamaev 已提交
200 201 202

}

A
Andrey Kamaev 已提交
203
setManualFunctions=set(['minMaxLoc', 'getTextSize'])
204

A
Andrey Kamaev 已提交
205 206 207 208 209 210 211
class ConstInfo(object):
    def __init__(self, cname, name, val):
        self.cname = cname
        self.name =  re.sub(r"^Cv", "", name)
        self.value = val


212 213 214 215 216 217
class ClassPropInfo(object):
    def __init__(self, decl): # [f_ctype, f_name, '', '/RW']
        self.ctype = decl[0]
        self.name = decl[1]
        self.rw = "/RW" in decl[3]

A
Andrey Kamaev 已提交
218 219 220 221 222 223 224 225
class ClassInfo(object):
    def __init__(self, decl): # [ 'class/struct cname', [bases], [modlist] ]
        name = decl[0]
        name = name[name.find(" ")+1:].strip()
        self.cname = self.name = self.jname = re.sub(r"^cv\.", "", name)
        self.cname =self.cname.replace(".", "::")
        self.methods = {}
        self.consts = [] # using a list to save the occurence order
226
        self.props= []
A
Andrey Kamaev 已提交
227 228 229 230 231 232 233
        for m in decl[2]:
            if m.startswith("="):
                self.jname = m[1:]


class ArgInfo(object):
    def __init__(self, arg_tuple): # [ ctype, name, def val, [mod], argno ]
234 235 236 237 238 239
        self.pointer = False
        ctype = arg_tuple[0]
        if ctype.endswith("*"):
            ctype = ctype[:-1]
            self.pointer = True
        self.ctype = ctype
A
Andrey Kamaev 已提交
240 241
        self.name = arg_tuple[1]
        self.defval = arg_tuple[2]
242 243 244 245 246
        self.out = ""
        if "/O" in arg_tuple[3]:
            self.out = "O"
        if "/IO" in arg_tuple[3]:
            self.out = "IO"
A
Andrey Kamaev 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266


class FuncInfo(object):
    def __init__(self, decl): # [ funcname, return_ctype, [modifiers], [args] ]
        name = re.sub(r"^cv\.", "", decl[0])
        self.cname = name.replace(".", "::")
        classname = ""
        dpos = name.rfind(".")
        if dpos >= 0:
            classname = name[:dpos]
            name = name[dpos+1:]
        self.classname = classname
        self.jname = self.name = name
        if "[" in name:
            self.jname = "getelem"
        for m in decl[2]:
            if m.startswith("="):
                self.jname = m[1:]
        self.jn_name = "n_" + self.jname
        self.jni_name= re.sub(r"_", "_1", self.jn_name)
267 268
##        if self.classname:
##            self.jni_name = "00024" + self.classname + "_" + self.jni_name
A
Andrey Kamaev 已提交
269 270 271
        self.static = ["","static"][ "/S" in decl[2] ]
        self.ctype = decl[1] or ""
        self.args = []
272 273 274
        #self.jni_suffix = "__"
        #if self.classname and self.ctype and not self.static: # non-static class methods except c-tors
        #    self.jni_suffix += "J" # artifical 'self'
A
Andrey Kamaev 已提交
275 276 277
        for a in decl[3]:
            ai = ArgInfo(a)
            self.args.append(ai)
278
        #    self.jni_suffix += ctype2j.get(ai.ctype, ["","","",""])[3]
A
Andrey Kamaev 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303



class FuncFamilyInfo(object):
    def __init__(self, decl): # [ funcname, return_ctype, [modifiers], [args] ]
        self.funcs = []
        self.funcs.append( FuncInfo(decl) )
        self.jname = self.funcs[0].jname
        self.isconstructor = self.funcs[0].name == self.funcs[0].classname



    def add_func(self, fi):
        self.funcs.append( fi )


class JavaWrapperGenerator(object):
    def __init__(self):
        self.clear()

    def clear(self):
        self.classes = { "Mat" : ClassInfo([ 'class Mat', [], [] ]) }
        self.funcs = {}
        self.consts = [] # using a list to save the occurence order
        self.module = ""
304 305 306
        self.Module = ""
        self.java_code= {} # { class : {j_code, jn_code} }
        self.cpp_code = None
307 308
        self.ported_func_list = []
        self.skipped_func_list = []
309 310 311 312 313 314 315 316 317

    def add_class_code_stream(self, class_name):
        self.java_code[class_name] = { "j_code" : StringIO(), "jn_code" : StringIO(), }
        self.java_code[class_name]["j_code"].write("""
//
// This file is auto-generated. Please don't modify it!
//
package org.opencv.%s;
%s
318
import org.opencv.utils;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
%s
public class %s {

""" % ( self.module,
        ("import org.opencv.core.*;", "")[self.module == "core"],
        ("// C++: class "+class_name+"\n//javadoc: "+class_name, "")[class_name == self.Module],
        class_name ) )

        if class_name != self.Module:
            self.java_code[class_name]["j_code"].write("""
    protected final long nativeObj;
    protected %s(long addr) { nativeObj = addr; }
""" % class_name )

        self.java_code[class_name]["jn_code"].write("""
    //
    // native stuff
    //
    static { System.loadLibrary("opencv_java"); }
""" )


A
Andrey Kamaev 已提交
341 342 343

    def add_class(self, decl):
        classinfo = ClassInfo(decl)
344 345
        if classinfo.name in class_ignore_list:
            return
A
Andrey Kamaev 已提交
346 347 348 349 350
        if classinfo.name in self.classes:
            print "Generator error: class %s (%s) is duplicated" % \
                    (classinfo.name, classinfo.cname)
            sys.exit(-1)
        self.classes[classinfo.name] = classinfo
351
        if classinfo.name in type_dict:
A
Andrey Kamaev 已提交
352 353
            print "Duplicated class: " + classinfo.name
            sys.exit(-1)
354
        type_dict[classinfo.name] = \
355 356 357
            { "j_type" : classinfo.name,
              "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
              "jni_name" : "(*("+classinfo.name+"*)%(n)s_nativeObj)", "jni_type" : "jlong",
358
              "suffix" : "J" }
359

360 361 362 363 364 365
        # class props
        for p in decl[3]:
            if "vector" not in p[0]:
                classinfo.props.append( ClassPropInfo(p) )
            else:
                print "Skipped proprty: [%s]" % classinfo.name, p
366

367
        self.add_class_code_stream(classinfo.name)
A
Andrey Kamaev 已提交
368 369 370 371 372 373 374


    def add_const(self, decl): # [ "const cname", val, [], [] ]
        consts = self.consts
        name = decl[0].replace("const ", "").strip()
        name = re.sub(r"^cv\.", "", name)
        cname = name.replace(".", "::")
375 376 377
        for c in const_ignore_list:
            if re.match(c, name):
                return
A
Andrey Kamaev 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
        # check if it's a class member
        dpos = name.rfind(".")
        if dpos >= 0:
            classname = name[:dpos]
            name = name[dpos+1:]
            if classname in self.classes:
                consts = self.classes[classname].consts
            else:
                # this class isn't wrapped
                # skipping this const
                return
        constinfo = ConstInfo(cname, name, decl[1])
        # checking duplication
        for c in consts:
            if c.name == constinfo.name:
                print "Generator error: constant %s (%s) is duplicated" \
                        % (constinfo.name, constinfo.cname)
                sys.exit(-1)
        consts.append(constinfo)

    def add_func(self, decl):
        ffi = FuncFamilyInfo(decl)
400
	if ffi.jname in setManualFunctions :
401
		print "Found function, which is ported manually: " + ffi.jname
402
		return None
A
Andrey Kamaev 已提交
403 404
        func_map = self.funcs
        classname = ffi.funcs[0].classname
405 406
        if classname in class_ignore_list or ffi.jname in func_ignore_list:
            return
A
Andrey Kamaev 已提交
407 408 409 410 411 412 413 414 415 416 417 418
        if classname:
            if classname in self.classes:
                func_map = self.classes[classname].methods
            else:
                print "Generator error: the class %s for method %s is missing" % \
                        (classname, ffi.jname)
                sys.exit(-1)
        if ffi.jname in func_map:
            func_map[ffi.jname].add_func(ffi.funcs[0])
        else:
            func_map[ffi.jname] = ffi

419 420
    def save(self, path, buf):
        f = open(path, "wt")
A
Andrey Kamaev 已提交
421 422 423 424 425 426
        f.write(buf.getvalue())
        f.close()

    def gen(self, srcfiles, module, output_path):
        self.clear()
        self.module = module
427
        self.Module = module.capitalize()
A
Andrey Kamaev 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
        parser = hdr_parser.CppHeaderParser()

        # step 1: scan the headers and build more descriptive maps of classes, consts, functions
        for hdr in srcfiles:
            decls = parser.parse(hdr)
            for decl in decls:
                name = decl[0]
                if name.startswith("struct") or name.startswith("class"):
                    self.add_class(decl)
                    pass
                elif name.startswith("const"):
                    self.add_const(decl)
                else: # function
                    self.add_func(decl)
                    pass

444 445
        self.add_class_code_stream(self.Module)
        self.cpp_code = StringIO()
A
Andrey Kamaev 已提交
446

447
        # java code
448
        if module == "core":
449
            self.java_code[self.Module]["j_code"].write(\
450 451
"""
    private static final int
452
            CV_8U  = 0, CV_8S  = 1, CV_16U = 2, CV_16S = 3, CV_32S = 4, CV_32F = 5, CV_64F = 6, CV_USRTYPE1 = 7;
453

454 455
    //Manual ported functions

456
    // C++: minMaxLoc(Mat src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    //javadoc: minMaxLoc
    public static class MinMaxLocResult {
        public double minVal;
        public double maxVal;
        public Point minLoc;
        public Point maxLoc;

	public MinMaxLocResult() {
	    minVal=0; maxVal=0;
	    minLoc=new Point();
	    maxLoc=new Point();
	}
    }
    public static MinMaxLocResult minMaxLoc(Mat src, Mat mask) {
        MinMaxLocResult res = new MinMaxLocResult();
        long maskNativeObj=0;
        if (mask != null) {
                maskNativeObj=mask.nativeObj;
        }
L
Leonid Beynenson 已提交
476
        double resarr[] = n_minMaxLocManual(src.nativeObj, maskNativeObj);
477 478 479 480 481 482 483 484 485 486 487
        res.minVal=resarr[0];
        res.maxVal=resarr[1];
        res.minLoc.x=resarr[2];
        res.minLoc.y=resarr[3];
        res.maxLoc.x=resarr[4];
        res.maxLoc.y=resarr[5];
        return res;
    }
    public static MinMaxLocResult minMaxLoc(Mat src) {
        return minMaxLoc(src, null);
    }
L
Leonid Beynenson 已提交
488
    private static native double[] n_minMaxLocManual(long src_nativeObj, long mask_nativeObj);
489

A
Andrey Kamaev 已提交
490 491 492 493 494 495 496
    //javadoc:getTextSize(text, fontFace, fontScale, thickness, baseLine)
    public static Size getTextSize(String text, int fontFace, double fontScale, int thickness, int[] baseLine) {
        assert(baseLine == null || baseLine.length == 1);
        Size retVal = new Size(n_getTextSize(text, fontFace, fontScale, thickness, baseLine));
        return retVal;
    }
    private static native double[] n_getTextSize(String text, int fontFace, double fontScale, int thickness, int[] baseLine);
497

498 499 500
""" )

        if module == "imgproc":
501
            self.java_code[self.Module]["j_code"].write(\
502
"""
503 504 505
    private static final int
            IPL_BORDER_CONSTANT = 0, IPL_BORDER_REPLICATE = 1, IPL_BORDER_REFLECT = 2,
            IPL_BORDER_WRAP = 3, IPL_BORDER_REFLECT_101 = 4, IPL_BORDER_TRANSPARENT = 5;
506
""" )
507

A
Andrey Pavlenko 已提交
508
        if module == "calib3d":
509
            self.java_code[self.Module]["j_code"].write(\
A
Andrey Pavlenko 已提交
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
"""
    public static final int
            CV_LMEDS = 4,
            CV_RANSAC = 8,
            CV_FM_LMEDS = CV_LMEDS,
            CV_FM_RANSAC = CV_RANSAC;

    public static final int
            CV_FM_7POINT = 1,
            CV_FM_8POINT = 2;

    public static final int
            CV_CALIB_USE_INTRINSIC_GUESS = 1,
            CV_CALIB_FIX_ASPECT_RATIO = 2,
            CV_CALIB_FIX_PRINCIPAL_POINT = 4,
            CV_CALIB_ZERO_TANGENT_DIST = 8,
            CV_CALIB_FIX_FOCAL_LENGTH = 16,
            CV_CALIB_FIX_K1 = 32,
            CV_CALIB_FIX_K2 = 64,
            CV_CALIB_FIX_K3 = 128,
            CV_CALIB_FIX_K4 = 2048,
            CV_CALIB_FIX_K5 = 4096,
            CV_CALIB_FIX_K6 = 8192,
            CV_CALIB_RATIONAL_MODEL = 16384,
            CV_CALIB_FIX_INTRINSIC = 256,
            CV_CALIB_SAME_FOCAL_LENGTH = 512,
            CV_CALIB_ZERO_DISPARITY = 1024;
""" )

539

A
Andrey Kamaev 已提交
540
        # cpp module header
541 542
        self.cpp_code.write("""
//
543 544
// This file is auto-generated, please don't edit!
//
A
Andrey Kamaev 已提交
545 546

#include <jni.h>
547 548

#ifdef DEBUG
549
#include <android/log.h>
550 551
#define MODULE_LOG_TAG "OpenCV.%s"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, MODULE_LOG_TAG, __VA_ARGS__))
552 553 554
#else //DEBUG
#define LOGD(...)
#endif //DEBUG
A
Andrey Kamaev 已提交
555

556
#include "utils.h"
557
""" % module)
A
Andrey Kamaev 已提交
558 559
        self.cpp_code.write( "\n".join(['#include "opencv2/%s/%s"' % (module, os.path.basename(f)) \
                            for f in srcfiles]) )
560
        self.cpp_code.write('\nusing namespace cv;\n')
561
        self.cpp_code.write('\n\nextern "C" {\n\n')
A
Andrey Kamaev 已提交
562 563

        # step 2: generate the code for global constants
564
        self.gen_consts(self.consts, self.java_code[self.Module]["j_code"])
A
Andrey Kamaev 已提交
565 566 567 568 569

        # step 3: generate the code for all the global functions
        self.gen_funcs()

        # step 4: generate code for the classes
570
        self.gen_classes()
A
Andrey Kamaev 已提交
571

572 573 574
        if module == "core":
            self.cpp_code.write(\
"""
575
JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Core_n_1minMaxLocManual
576 577 578
  (JNIEnv* env, jclass cls, jlong src_nativeObj, jlong mask_nativeObj)
{
    try {
579
        LOGD("Core::n_1minMaxLoc()");
580 581 582 583 584
        jdoubleArray result;
        result = env->NewDoubleArray(6);
        if (result == NULL) {
            return NULL; /* out of memory error thrown */
        }
585

586
        Mat& src = *((Mat*)src_nativeObj);
587

588 589 590 591 592 593 594 595
        double minVal, maxVal;
        Point minLoc, maxLoc;
        if (mask_nativeObj != 0) {
            Mat& mask = *((Mat*)mask_nativeObj);
            minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc, mask);
        } else {
            minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc);
        }
596

597 598 599 600 601 602 603
        jdouble fill[6];
        fill[0]=minVal;
        fill[1]=maxVal;
        fill[2]=minLoc.x;
        fill[3]=minLoc.y;
        fill[4]=maxLoc.x;
        fill[5]=maxLoc.y;
604

605 606 607 608 609
        env->SetDoubleArrayRegion(result, 0, 6, fill);

	return result;

    } catch(cv::Exception e) {
610
        LOGD("Core::n_1minMaxLoc() catched cv::Exception: %s", e.what());
611 612 613 614 615
        jclass je = env->FindClass("org/opencv/CvException");
        if(!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return NULL;
    } catch (...) {
616
        LOGD("Core::n_1minMaxLoc() catched unknown exception (...)");
617
        jclass je = env->FindClass("java/lang/Exception");
A
Andrey Kamaev 已提交
618 619 620 621 622
        env->ThrowNew(je, "Unknown exception in JNI code {core::minMaxLoc()}");
        return NULL;
    }
}

623
JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Core_n_1getTextSize
A
Andrey Kamaev 已提交
624 625 626
  (JNIEnv* env, jclass cls, jstring text, jint fontFace, jdouble fontScale, jint thickness, jintArray baseLine)
{
    try {
627
        LOGD("Core::n_1getTextSize()");
A
Andrey Kamaev 已提交
628 629 630 631 632
        jdoubleArray result;
        result = env->NewDoubleArray(2);
        if (result == NULL) {
            return NULL; /* out of memory error thrown */
        }
633

A
Andrey Kamaev 已提交
634 635 636
        const char* utf_text = env->GetStringUTFChars(text, 0);
        std::string n_text( utf_text ? utf_text : "" );
        env->ReleaseStringUTFChars(text, utf_text);
637

A
Andrey Kamaev 已提交
638 639
        int _baseLine;
        int* pbaseLine = 0;
640

A
Andrey Kamaev 已提交
641 642
        if (baseLine != NULL)
            pbaseLine = &_baseLine;
643

A
Andrey Kamaev 已提交
644 645 646 647 648 649 650
        cv::Size rsize = cv::getTextSize(n_text, (int)fontFace, (double)fontScale, (int)thickness, pbaseLine);

        jdouble fill[2];
        fill[0]=rsize.width;
        fill[1]=rsize.height;

        env->SetDoubleArrayRegion(result, 0, 2, fill);
651

A
Andrey Kamaev 已提交
652 653 654 655 656 657
        if (baseLine != NULL)
            env->SetIntArrayRegion(baseLine, 0, 1, pbaseLine);

        return result;

    } catch(cv::Exception e) {
658
        LOGD("Core::n_1getTextSize() catched cv::Exception: %s", e.what());
A
Andrey Kamaev 已提交
659 660 661 662 663
        jclass je = env->FindClass("org/opencv/CvException");
        if(!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return NULL;
    } catch (...) {
664
        LOGD("Core::n_1getTextSize() catched unknown exception (...)");
A
Andrey Kamaev 已提交
665 666
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {core::getTextSize()}");
667 668 669 670
        return NULL;
    }
}
""")
671 672 673 674
        # saving code streams
        for cls in self.java_code.keys():
            self.java_code[cls]["j_code"].write("\n\n%s\n}\n" % self.java_code[cls]["jn_code"].getvalue())
            self.save("%s/%s+%s.java" % (output_path, module, cls), self.java_code[cls]["j_code"])
675

676 677
        self.cpp_code.write( '\n} // extern "C"\n' )
        self.save(output_path+"/"+module+".cpp",  self.cpp_code)
A
Andrey Kamaev 已提交
678

679 680 681
        # report
        report = StringIO()
        report.write("PORTED FUNCs LIST (%i of %i):\n\n" % \
682
            (len(self.ported_func_list), len(self.ported_func_list)+ len(self.skipped_func_list))
683 684 685
        )
        report.write("\n".join(self.ported_func_list))
        report.write("\n\nSKIPPED FUNCs LIST (%i of %i):\n\n" % \
686
            (len(self.skipped_func_list), len(self.ported_func_list)+ len(self.skipped_func_list))
687 688
        )
        report.write("".join(self.skipped_func_list))
689
        self.save(output_path+"/"+module+".txt", report)
A
Andrey Kamaev 已提交
690

691
        print "Done %i of %i funcs." % (len(self.ported_func_list), len(self.ported_func_list)+ len(self.skipped_func_list))
A
Andrey Kamaev 已提交
692 693


694 695 696 697

    def gen_consts(self, consts, code_stream):
        if consts:
            code_stream.write("""
A
Andrey Kamaev 已提交
698
    public static final int
699
            %s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in consts])
700
            )
A
Andrey Kamaev 已提交
701 702


703
    def gen_func(self, fi, isoverload):
704
        # // C++: c_decl
705
        # e.g: //  C++: void add(Mat src1, Mat src2, Mat dst, Mat mask = Mat(), int dtype = -1)
706 707 708 709 710 711 712 713 714 715 716 717 718
        decl_args = []
        for a in fi.args:
            s = a.ctype
            if a.pointer:
                s += "*"
            elif a.out:
                s += "&"
            s += " " + a.name
            if a.defval:
                s += " = "+a.defval
            decl_args.append(s)
        c_decl = "%s %s %s(%s)" % ( fi.static, fi.ctype, fi.cname, ", ".join(decl_args) )

719 720 721 722 723 724 725 726 727 728
        #java doc comment
        f_name = fi.name
        if fi.classname:
            f_name = fi.classname + "::" + fi.name
        java_doc = "//javadoc: " + f_name + "(%s)" % ", ".join([a.name for a in fi.args])

        self.gen_func2(fi, isoverload, c_decl, java_doc, "")


    def gen_func2(self, fi, isoverload, c_decl, java_doc, prop_name):
729 730 731
        j_code   = self.java_code[self.Module]["j_code"]
        jn_code  = self.java_code[self.Module]["jn_code"]
        cpp_code = self.cpp_code
A
Andrey Kamaev 已提交
732
        if fi.classname:
733 734 735
            j_code   = self.java_code[fi.classname]["j_code"]
            jn_code  = self.java_code[fi.classname]["jn_code"]

736
        # java comment
737
        j_code.write( "\n    //\n    // C++: %s\n    //\n\n" % c_decl )
A
Andrey Kamaev 已提交
738
        # check if we 'know' all the types
739
        if fi.ctype not in type_dict: # unsupported ret type
740
            msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
741
            self.skipped_func_list.append(c_decl + "\n" + msg)
742
            j_code.write( " "*4 + msg )
A
Andrey Kamaev 已提交
743 744 745
            print "SKIP:", c_decl, "\n\tdue to RET type", fi.ctype
            return
        for a in fi.args:
746
            if a.ctype not in type_dict:
747
                msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I")
748
                self.skipped_func_list.append(c_decl + "\n" + msg)
749
                j_code.write( " "*4 + msg )
750
                print "SKIP:", c_decl, "\n\tdue to ARG type", a.ctype, "/" + (a.out or "I")
A
Andrey Kamaev 已提交
751 752
                return

753
        self.ported_func_list.append(c_decl)
754

755
        # jn & cpp comment
756 757
        jn_code.write( "\n    // C++: %s\n" % c_decl )
        cpp_code.write( "\n//\n// %s\n//\n" % c_decl )
758

A
Andrey Kamaev 已提交
759
        # java args
760
        args = fi.args[:] # copy
A
Andrey Kamaev 已提交
761 762 763 764 765
        if args and args[-1].defval:
            isoverload = True

        while True:

766
             # java native method args
A
Andrey Kamaev 已提交
767 768 769
            jn_args = []
            # jni (cpp) function args
            jni_args = [ArgInfo([ "env", "env", "", [], "" ]), ArgInfo([ "cls", "cls", "", [], "" ])]
770
            suffix = "__"
771 772 773 774 775
            j_prologue = []
            j_epilogue = []
            c_prologue = []
            c_epilogue = []
            if type_dict[fi.ctype]["jni_type"] == "jdoubleArray":
776 777 778 779 780 781
                fields = type_dict[fi.ctype]["jn_args"]
                c_epilogue.append( \
                    ("jdoubleArray _da_retval_ = env->NewDoubleArray(%(cnt)i);  " +
                     "jdouble _tmp_retval_[%(cnt)i] = {%(args)s}; " +
                     "env->SetDoubleArrayRegion(_da_retval_, 0, %(cnt)i, _tmp_retval_);") %
                    { "cnt" : len(fields), "args" : ", ".join(["_retval_" + f[1] for f in fields]) } )
782 783 784 785 786
            if fi.classname and fi.ctype and not fi.static: # non-static class method except c-tor
                # adding 'self'
                jn_args.append ( ArgInfo([ "__int64", "nativeObj", "", [], "" ]) )
                jni_args.append( ArgInfo([ "__int64", "self", "", [], "" ]) )
                suffix += "J"
A
Andrey Kamaev 已提交
787
            for a in args:
788
                suffix += type_dict[a.ctype].get("suffix") or ""
789 790 791 792 793

                if "vector" in a.ctype: # pass as Mat
                    jn_args.append  ( ArgInfo([ "__int64", "%s_mat.nativeObj" % a.name, "", [], "" ]) )
                    jni_args.append ( ArgInfo([ "__int64", "%s_mat_nativeObj" % a.name, "", [], "" ]) )
                    c_prologue.append( type_dict[a.ctype]["jni_var"] % {"n" : a.name} + ";" )
794
                    c_prologue.append( "Mat& %(n)s_mat = *((Mat*)%(n)s_mat_nativeObj)" % {"n" : a.name} + ";" )
795
                    if "I" in a.out or not a.out:
796 797
                        j_prologue.append( "Mat %(n)s_mat = utils.%(t)s_to_Mat(%(n)s);" % {"n" : a.name, "t" : a.ctype} )
                        c_prologue.append( "Mat_to_%(t)s( %(n)s_mat, %(n)s );" % {"n" : a.name, "t" : a.ctype} )
798 799 800
                    else:
                        j_prologue.append( "Mat %s_mat = new Mat();" % a.name )
                    if "O" in a.out:
801
                        j_epilogue.append("utils.Mat_to_%(t)s(%(n)s_mat, %(n)s);" % {"t" : a.ctype, "n" : a.name})
802
                        c_epilogue.append( "%(t)s_to_Mat( %(n)s, %(n)s_mat );" % {"n" : a.name, "t" : a.ctype} )
A
Andrey Kamaev 已提交
803
                else:
804

805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
                    fields = type_dict[a.ctype].get("jn_args", ((a.ctype, ""),))
                    if "I" in a.out or not a.out or a.ctype in self.classes: # input arg, pass by primitive fields
                        for f in fields:
                            jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
                            jni_args.append( ArgInfo([ f[0], a.name + f[1].replace(".","_").replace("[","").replace("]",""), "", [], "" ]) )
                    if a.out and a.ctype not in self.classes: # out arg, pass as double[]
                        jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
                        jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
                        j_prologue.append( "double[] %s_out = new double[%i];" % (a.name, len(fields)) )
                        set_vals = []
                        i = 0
                        for f in fields:
                            set_vals.append( "%(n)s%(f)s = %(t)s%(n)s_out[%(i)i]" %
                                {"n" : a.name, "t": ("("+type_dict[f[0]]["j_type"]+")", "")[f[0]=="double"], "f" : f[1], "i" : i}
                            )
                            i += 1
                        #j_epilogue.append("%s.set(%s_out);" % (a.name, a.name))
                        j_epilogue.append("; ".join(set_vals) + "; ")
                        c_epilogue.append( \
                            "jdouble tmp_%(n)s[%(cnt)i] = {%(args)s}; env->SetDoubleArrayRegion(%(n)s_out, 0, %(cnt)i, tmp_%(n)s);" %
                            { "n" : a.name, "cnt" : len(fields), "args" : ", ".join([a.name + f[1] for f in fields]) } )
826

A
Andrey Kamaev 已提交
827 828 829 830 831

            # java part:
            # private java NATIVE method decl
            # e.g.
            # private static native void n_add(long src1, long src2, long dst, long mask, int dtype);
832
            jn_code.write( Template(\
833
                "    private static native $jn_type $jn_name($jn_args);\n").substitute(\
834
                jn_type = type_dict[fi.ctype].get("jn_type", "double[]"), \
835
                jn_name = fi.jn_name, \
836
                jn_args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], a.name.replace(".","_").replace("[","").replace("]","")) for a in jn_args])
A
Andrey Kamaev 已提交
837 838 839
            ) );

            # java part:
840 841

            #java doc comment
842 843 844 845
##            f_name = fi.name
##            if fi.classname:
##                f_name = fi.classname + "::" + fi.name
            j_code.write(" "*4 + java_doc + "\n")
846

A
Andrey Kamaev 已提交
847 848 849 850
            # public java wrapper method impl (calling native one above)
            # e.g.
            # public static void add( Mat src1, Mat src2, Mat dst, Mat mask, int dtype )
            # { n_add( src1.nativeObj, src2.nativeObj, dst.nativeObj, mask.nativeObj, dtype );  }
851 852 853
            ret_val = type_dict[fi.ctype]["j_type"] + " retVal = "
            tail = ""
            ret = "return retVal;"
A
Andrey Kamaev 已提交
854
            if fi.ctype == "void":
855 856
                ret_val = ""
                ret = "return;"
A
Andrey Kamaev 已提交
857
            elif fi.ctype == "": # c-tor
858 859
                ret_val = "nativeObj = "
                ret = "return;"
A
Andrey Kamaev 已提交
860
            elif fi.ctype in self.classes: # wrapped class
861 862
                ret_val = type_dict[fi.ctype]["j_type"] + " retVal = new " + self.classes[fi.ctype].jname + "("
                tail = ")"
863
            elif "jn_type" not in type_dict[fi.ctype]:
864 865
                ret_val = type_dict[fi.ctype]["j_type"] + " retVal = new " + type_dict[fi.ctype]["j_type"] + "("
                tail = ")"
A
Andrey Kamaev 已提交
866 867 868 869 870

            static = "static"
            if fi.classname:
                static = fi.static

871 872 873 874 875 876 877 878
            j_code.write( Template(\
"""    public $static $j_type $j_name($j_args)
    {
        $prologue
        $ret_val$jn_name($jn_args_call)$tail;
        $epilogue
        $ret
    }
A
Andrey Kamaev 已提交
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
"""
                ).substitute(\
                    ret = ret, \
                    ret_val = ret_val, \
                    tail = tail, \
                    prologue = "  ".join(j_prologue), \
                    epilogue = "  ".join(j_epilogue), \
                    static=static, \
                    j_type=type_dict[fi.ctype]["j_type"], \
                    j_name=fi.jname, \
                    j_args=", ".join(["%s %s" % (type_dict[a.ctype]["j_type"], a.name) for a in args]), \
                    jn_name=fi.jn_name, \
                    jn_args_call=", ".join( [a.name for a in jn_args] ),\
                )
            )
A
Andrey Kamaev 已提交
895 896

            # cpp part:
897 898
            # jni_func(..) { _retval_ = cv_func(..); return _retval_; }
            ret = "return _retval_;"
899
            default = "return 0;"
A
Andrey Kamaev 已提交
900
            if fi.ctype == "void":
901 902 903 904
                ret = "return;"
                default = "return;"
            elif not fi.ctype: # c-tor
                ret = "return (jlong) _retval_;"
905
            elif fi.ctype == "string":
906
                ret = "return env->NewStringUTF(_retval_.c_str());"
907
                default = 'return env->NewStringUTF("");'
908
            elif fi.ctype in self.classes: # wrapped class:
909
                ret = "return (jlong) new %s(_retval_);" % fi.ctype
910
            elif type_dict[fi.ctype]["jni_type"] == "jdoubleArray":
911
                ret = "return _da_retval_;"
A
Andrey Kamaev 已提交
912

913 914 915 916 917 918 919 920 921
            # hack: replacing func call with property set/get
            name = fi.name
            if prop_name:
                if args:
                    name = prop_name + " = "
                else:
                    name = prop_name + ";//"

            cvname = "cv::" + name
922 923 924
            retval = fi.ctype + " _retval_ = "
            if fi.ctype == "void":
                retval = ""
A
Andrey Kamaev 已提交
925 926
            if fi.classname:
                if not fi.ctype: # c-tor
927 928
                    retval = fi.classname + "* _retval_ = "
                    cvname = "new " + fi.classname
A
Andrey Kamaev 已提交
929
                elif fi.static:
930
                    cvname = "%s::%s" % (fi.classname, name)
A
Andrey Kamaev 已提交
931
                else:
932
                    cvname = "me->" + name
933
                    c_prologue.append(\
934
                        "%(cls)s* me = (%(cls)s*) self; //TODO: check for NULL" \
935
                            % { "cls" : fi.classname} \
A
Andrey Kamaev 已提交
936 937 938
                    )
            cvargs = []
            for a in args:
939 940 941 942 943 944 945 946 947 948
                if a.pointer:
                    jni_name = "&%(n)s"
                else:
                    jni_name = "%(n)s"
                cvargs.append( type_dict[a.ctype].get("jni_name", jni_name) % {"n" : a.name})
                if "vector" not in a.ctype :
                    if ("I" in a.out or not a.out or a.ctype in self.classes) and "jni_var" in type_dict[a.ctype]: # complex type
                        c_prologue.append(type_dict[a.ctype]["jni_var"] % {"n" : a.name} + ";")
                    if a.out and "I" not in a.out and a.ctype not in self.classes:
                        c_prologue.append("%s %s;" % (a.ctype, a.name))
A
Andrey Kamaev 已提交
949

950
            rtype = type_dict[fi.ctype].get("jni_type", "jdoubleArray")
951
            cpp_code.write ( Template( \
A
Andrey Kamaev 已提交
952 953
"""

954
JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
A
Andrey Kamaev 已提交
955 956
  ($args)
{
957
    try {
958
        LOGD("$module::$fname()");
959
        $prologue
960
        $retval$cvname( $cvargs );
961
        $epilogue
962
        $ret
963
    } catch(cv::Exception e) {
964
        LOGD("$module::$fname() catched cv::Exception: %s", e.what());
965 966 967
        jclass je = env->FindClass("org/opencv/CvException");
        if(!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
968
        $default
969
    } catch (...) {
970
        LOGD("$module::$fname() catched unknown exception (...)");
971 972
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {$module::$fname()}");
973
        $default
974
    }
A
Andrey Kamaev 已提交
975 976
}

977

A
Andrey Kamaev 已提交
978 979 980
""" ).substitute( \
        rtype = rtype, \
        module = self.module, \
981
        clazz = fi.classname or self.Module, \
A
Andrey Kamaev 已提交
982
        fname = fi.jni_name + ["",suffix][isoverload], \
983
        args = ", ".join(["%s %s" % (type_dict[a.ctype].get("jni_type"), a.name) for a in jni_args]), \
984 985
        prologue = "\n        ".join(c_prologue), \
        epilogue = "  ".join(c_epilogue), \
A
Andrey Kamaev 已提交
986 987 988
        ret = ret, \
        cvname = cvname, \
        cvargs = ", ".join([a for a in cvargs]), \
989 990
        default = default, \
        retval = retval, \
A
Andrey Kamaev 已提交
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    ) )

            # processing args with default values
            if args and args[-1].defval:
                a = args.pop()
            else:
                break



    def gen_funcs(self):
        # generate the code for all the global functions
        fflist = self.funcs.items()
        fflist.sort()
        for name, ffi in fflist:
            assert not ffi.funcs[0].classname, "Error: global func is a class member - "+name
            for fi in ffi.funcs:
1008
                self.gen_func(fi, len(ffi.funcs)>1)
A
Andrey Kamaev 已提交
1009 1010 1011 1012 1013 1014 1015


    def gen_classes(self):
        # generate code for the classes (their methods and consts)
        classlist = self.classes.items()
        classlist.sort()
        for name, ci in classlist:
1016
            if name == "Mat":
1017
                continue
A
Andrey Kamaev 已提交
1018
            # constants
1019
            self.gen_consts(ci.consts, self.java_code[name]["j_code"])
A
Andrey Kamaev 已提交
1020 1021 1022 1023 1024 1025
            # c-tors
            fflist = ci.methods.items()
            fflist.sort()
            for n, ffi in fflist:
                if ffi.isconstructor:
                    for fi in ffi.funcs:
1026 1027
                        self.gen_func(fi, len(ffi.funcs)>1)
            # other methods
A
Andrey Kamaev 已提交
1028 1029 1030
            for n, ffi in fflist:
                if not ffi.isconstructor:
                    for fi in ffi.funcs:
1031
                        self.gen_func(fi, len(ffi.funcs)>1)
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
            # props
            for pi in ci.props:
                # getter
                getter_name = name + ".get_" + pi.name
                #print getter_name
                fi = FuncInfo( [getter_name, pi.ctype, [], []] ) # [ funcname, return_ctype, [modifiers], [args] ]
                self.gen_func2(fi, getter_name in ci.methods, "// %s %s" % (pi.ctype, pi.name), "//javadoc: %s::%s" % (name, pi.name), pi.name)
                if pi.rw:
                    #setter
                    setter_name = name + ".set_" + pi.name
                    #print setter_name
                    fi = FuncInfo( [ setter_name, "void", [], [ [pi.ctype, pi.name, "", [], ""] ] ] )
                    self.gen_func2(fi, getter_name in ci.methods, "// %s %s" % (pi.ctype, pi.name), "//javadoc: %s::%s" % (name, pi.name), pi.name)
A
Andrey Kamaev 已提交
1045

1046
            # finalize()
1047
            self.java_code[name]["j_code"].write(
1048
"""
1049 1050 1051 1052 1053
    @Override
    protected void finalize() throws Throwable {
        n_delete(nativeObj);
        super.finalize();
    }
1054
""" )
1055

1056
            self.java_code[name]["jn_code"].write(
1057
"""
1058 1059 1060
    // native support for java finalize()
    private static native void n_delete(long nativeObj);
""" )
1061 1062 1063 1064 1065 1066 1067 1068 1069

            # native support for java finalize()
            self.cpp_code.write( \
"""
//
//  native support for java finalize()
//  static void %(cls)s::n_delete( __int64 self )
//

1070
JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(cls)s_n_1delete
1071 1072 1073 1074 1075 1076 1077
  (JNIEnv* env, jclass cls, jlong self)
{
    delete (%(cls)s*) self;
}

""" % {"module" : module, "cls" : name}
            )
A
Andrey Kamaev 已提交
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099


if __name__ == "__main__":
    if len(sys.argv) < 4:
        print "Usage:\n", \
            os.path.basename(sys.argv[0]), \
            "<full path to hdr_parser.py> <module name> <C++ header> [<C++ header>...]"
        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
    module = sys.argv[2]
    srcfiles = sys.argv[3:]
    print "Generating module '" + module + "' from headers:\n\t" + "\n\t".join(srcfiles)
    generator = JavaWrapperGenerator()
    generator.gen(srcfiles, module, dstdir)