From 5c56b8ce9251050a4aadb9570ee598aaa14a2cf4 Mon Sep 17 00:00:00 2001 From: Ahmed Ashour Date: Wed, 5 Jun 2019 12:44:03 +0200 Subject: [PATCH] java: generated code to have javadoc --- CMakeLists.txt | 2 + doc/CMakeLists.txt | 2 - modules/calib3d/include/opencv2/calib3d.hpp | 23 +- modules/core/include/opencv2/core.hpp | 6 +- .../cudaarithm/include/opencv2/cudaarithm.hpp | 6 +- .../features2d/include/opencv2/features2d.hpp | 2 +- modules/java/generator/gen_java.py | 197 ++++++++++++++++-- .../generator/templates/java_class.prolog | 3 +- .../templates/java_class_inherited.prolog | 3 +- .../generator/templates/java_module.prolog | 3 +- modules/java/jar/build.xml.in | 21 +- modules/ml/include/opencv2/ml.hpp | 2 +- modules/python/src2/hdr_parser.py | 2 +- modules/videoio/include/opencv2/videoio.hpp | 4 +- 14 files changed, 222 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ed7e41be30e..a3d2b0a96a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,8 @@ endif() option(ENABLE_PIC "Generate position independent code (necessary for shared libraries)" TRUE) set(CMAKE_POSITION_INDEPENDENT_CODE ${ENABLE_PIC}) +set(OPENCV_MATHJAX_RELPATH "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0" CACHE STRING "URI to a MathJax installation") + # Following block can break build in case of cross-compiling # but CMAKE_CROSSCOMPILING variable will be set only on project(OpenCV) command # so we will try to detect cross-compiling by the presence of CMAKE_TOOLCHAIN_FILE diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 1619466be894..ccd27cb6fb87 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -19,8 +19,6 @@ if(DOXYGEN_FOUND) unset(CMAKE_DOXYGEN_TUTORIAL_CONTRIB_ROOT) unset(CMAKE_DOXYGEN_TUTORIAL_JS_ROOT) - set(OPENCV_MATHJAX_RELPATH "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0" CACHE STRING "URI to a MathJax installation") - # gathering headers set(paths_include) set(paths_doc) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index ac41213c4183..4ae44f7ec293 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -476,15 +476,14 @@ CV_EXPORTS_W void matMulDeriv( InputArray A, InputArray B, OutputArray dABdA, Ou @param tvec2 Second translation vector. @param rvec3 Output rotation vector of the superposition. @param tvec3 Output translation vector of the superposition. -@param dr3dr1 -@param dr3dt1 -@param dr3dr2 -@param dr3dt2 -@param dt3dr1 -@param dt3dt1 -@param dt3dr2 -@param dt3dt2 Optional output derivatives of rvec3 or tvec3 with regard to rvec1, rvec2, tvec1 and -tvec2, respectively. +@param dr3dr1 Optional output derivative of rvec3 with regard to rvec1 +@param dr3dt1 Optional output derivative of rvec3 with regard to tvec1 +@param dr3dr2 Optional output derivative of rvec3 with regard to rvec2 +@param dr3dt2 Optional output derivative of rvec3 with regard to tvec2 +@param dt3dr1 Optional output derivative of tvec3 with regard to rvec1 +@param dt3dt1 Optional output derivative of tvec3 with regard to tvec1 +@param dt3dr2 Optional output derivative of tvec3 with regard to rvec2 +@param dt3dt2 Optional output derivative of tvec3 with regard to tvec2 The functions compute: @@ -2754,7 +2753,7 @@ namespace fisheye @param D Input vector of distortion coefficients \f$(k_1, k_2, k_3, k_4)\f$. @param Knew Camera matrix of the distorted image. By default, it is the identity matrix but you may additionally scale and shift the result by using a different matrix. - @param new_size + @param new_size the new size The function transforms an image to compensate radial and tangential lens distortion. @@ -2780,14 +2779,14 @@ namespace fisheye /** @brief Estimates new camera matrix for undistortion or rectification. @param K Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}\f$. - @param image_size + @param image_size Size of the image @param D Input vector of distortion coefficients \f$(k_1, k_2, k_3, k_4)\f$. @param R Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 1-channel or 1x1 3-channel @param P New camera matrix (3x3) or new projection matrix (3x4) @param balance Sets the new focal length in range between the min focal length and the max focal length. Balance is in range of [0, 1]. - @param new_size + @param new_size the new size @param fov_scale Divisor for new focal length. */ CV_EXPORTS_W void estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R, diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index 089c0db33420..ecd773e7df36 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -311,9 +311,9 @@ if src was not a ROI, use borderType | #BORDER_ISOLATED. @param src Source image. @param dst Destination image of the same type as src and the size Size(src.cols+left+right, src.rows+top+bottom) . -@param top -@param bottom -@param left +@param top the top pixels +@param bottom the bottom pixels +@param left the left pixels @param right Parameter specifying how many pixels in each direction from the source image rectangle to extrapolate. For example, top=1, bottom=1, left=1, right=1 mean that 1 pixel-wide border needs to be built. diff --git a/modules/cudaarithm/include/opencv2/cudaarithm.hpp b/modules/cudaarithm/include/opencv2/cudaarithm.hpp index a1c4fa8ed845..10c0b5a958ac 100644 --- a/modules/cudaarithm/include/opencv2/cudaarithm.hpp +++ b/modules/cudaarithm/include/opencv2/cudaarithm.hpp @@ -505,9 +505,9 @@ CV_EXPORTS Ptr createLookUpTable(InputArray lut); @param src Source image. CV_8UC1 , CV_8UC4 , CV_32SC1 , and CV_32FC1 types are supported. @param dst Destination image with the same type as src. The size is Size(src.cols+left+right, src.rows+top+bottom) . -@param top -@param bottom -@param left +@param top Number of top pixels +@param bottom Number of bottom pixels +@param left Number of left pixels @param right Number of pixels in each direction from the source image rectangle to extrapolate. For example: top=1, bottom=1, left=1, right=1 mean that 1 pixel-wide border needs to be built. @param borderType Border type. See borderInterpolate for details. BORDER_REFLECT101 , diff --git a/modules/features2d/include/opencv2/features2d.hpp b/modules/features2d/include/opencv2/features2d.hpp index ee81ebe38562..4e68f2388d0b 100644 --- a/modules/features2d/include/opencv2/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d.hpp @@ -328,7 +328,7 @@ class CV_EXPORTS_W ORB : public Feature2D but it is a little faster to compute. @param patchSize size of the patch used by the oriented BRIEF descriptor. Of course, on smaller pyramid layers the perceived image area covered by a feature will be larger. - @param fastThreshold + @param fastThreshold the fast threshold */ CV_WRAP static Ptr create(int nfeatures=500, float scaleFactor=1.2f, int nlevels=8, int edgeThreshold=31, int firstLevel=0, int WTA_K=2, int scoreType=ORB::HARRIS_SCORE, int patchSize=31, int fastThreshold=20); diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index 14014e434c59..75ae87ac678f 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -3,6 +3,7 @@ import sys, re, os.path, errno, fnmatch import json import logging +import codecs from shutil import copyfile from pprint import pformat from string import Template @@ -105,14 +106,19 @@ def __init__(self, type, decl, namespaces): self.params={} self.annotation=[] if type == "class": - docstring="// C++: class " + self.name + "\n//javadoc: " + self.name + docstring="// C++: class " + self.name + "\n" else: docstring="" + if len(decl)>5 and decl[5]: - #logging.info('docstring: %s', decl[5]) - if re.search("(@|\\\\)deprecated", decl[5]): + doc = decl[5] + + #logging.info('docstring: %s', doc) + if re.search("(@|\\\\)deprecated", doc): self.annotation.append("@Deprecated") + docstring += sanitize_java_documentation_string(doc, type) + self.docstring = docstring def parseName(self, name, namespaces): @@ -263,7 +269,7 @@ def addConst(self, constinfo): def initCodeStreams(self, Module): self.j_code = StringIO() self.jn_code = StringIO() - self.cpp_code = StringIO(); + self.cpp_code = StringIO() if self.base: self.j_code.write(T_JAVA_START_INHERITED) else: @@ -293,7 +299,7 @@ def generateJavaCode(self, m, M): jname = self.jname, imports = "\n".join(self.getAllImports(M)), docs = self.docstring, - annotation = "\n".join(self.annotation), + annotation = "\n" + "\n".join(self.annotation) if self.annotation else "", base = self.base) def generateCppCode(self): @@ -481,7 +487,7 @@ def save(self, path, buf): content = f.read() if content == buf: return - with open(path, "wt") as f: + with codecs.open(path, "w", "utf-8") as f: f.write(buf) updated_files += 1 @@ -495,7 +501,7 @@ def gen(self, srcfiles, module, output_path, output_jni_path, output_java_path, self.add_class( ['class ' + self.Module, '', [], []] ) # [ 'class/struct cname', ':bases', [modlist] [props] ] # scan the headers and build more descriptive maps of classes, consts, functions - includes = []; + includes = [] for hdr in common_headers: logging.info("\n===== Common header : %s =====", hdr) includes.append('#include "' + hdr + '"') @@ -714,7 +720,7 @@ def gen_func(self, ci, fi, prop_name=''): fi.jname + "(" + ", ".join(j_args) + ")" logging.info("java: " + j_signature) - if(j_signature in j_signatures): + if j_signature in j_signatures: if args: args.pop() continue @@ -730,20 +736,51 @@ def gen_func(self, ci, fi, prop_name=''): type = type_dict[fi.ctype].get("jn_type", "double[]"), name = fi.jname + '_' + str(suffix_counter), args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], normalize_field_name(a.name)) for a in jn_args]) - ) ); + ) ) # java part: #java doc comment - f_name = fi.jname - if fi.classname: - f_name = fi.classname + "::" + fi.jname - java_doc = "//javadoc: " + f_name + "(%s)" % ", ".join([a.name for a in args if a.ctype]) - j_code.write(" "*4 + java_doc + "\n") - if fi.docstring: - lines = StringIO(fi.docstring) - for line in lines: + lines = fi.docstring.splitlines() + returnTag = False + javadocParams = [] + toWrite = [] + inCode = False + for index, line in enumerate(lines): + p0 = line.find("@param") + if p0 != -1: + p0 += 7 + p1 = line.find(' ', p0) + p1 = len(line) if p1 == -1 else p1 + name = line[p0:p1] + javadocParams.append(name) + for arg in j_args: + if arg.endswith(" " + name): + toWrite.append(line); + break + else: + if "" in line: + inCode = True + if "" in line: + inCode = False + if "@return " in line: + returnTag = True + + if (not inCode and toWrite and not toWrite[-1] and + line and not line.startswith("\\") and not line.startswith("
    ") and not line.startswith("@param")): + toWrite.append("

    "); + + if index == len(lines) - 1: + for arg in j_args: + name = arg[arg.rfind(' ') + 1:] + if not name in javadocParams: + toWrite.append(" * @param " + name + " automatically generated"); + if type_dict[fi.ctype]["j_type"] and not returnTag and fi.ctype != "void": + toWrite.append(" * @return automatically generated"); + toWrite.append(line); + + for line in toWrite: j_code.write(" "*4 + line + "\n") if fi.annotation: j_code.write(" "*4 + "\n".join(fi.annotation) + "\n") @@ -770,7 +807,7 @@ def gen_func(self, ci, fi, prop_name=''): j_epilogue.append('Converters.Mat_to_' + ret_type + '(retValMat, retVal);') ret = "return retVal;" elif ret_type.startswith("Ptr_"): - constructor = type_dict[ret_type]["j_type"] + ".__fromPtr__("; + constructor = type_dict[ret_type]["j_type"] + ".__fromPtr__(" if j_epilogue: ret_val = type_dict[fi.ctype]["j_type"] + " retVal = " + constructor else: @@ -787,14 +824,14 @@ def gen_func(self, ci, fi, prop_name=''): ret_val = "nativeObj = " ret = "" elif self.isWrapped(ret_type): # wrapped class - constructor = self.getClass(ret_type).jname + "("; + constructor = self.getClass(ret_type).jname + "(" if j_epilogue: ret_val = type_dict[ret_type]["j_type"] + " retVal = new " + constructor else: ret_val = "return new " + constructor tail = ")" elif "jn_type" not in type_dict[ret_type]: - constructor = type_dict[ret_type]["j_type"] + "("; + constructor = type_dict[ret_type]["j_type"] + "(" if j_epilogue: ret_val = type_dict[fi.ctype]["j_type"] + " retVal = new " + constructor else: @@ -806,7 +843,7 @@ def gen_func(self, ci, fi, prop_name=''): static = fi.static j_code.write( Template( -""" public $static$j_type $j_name($j_args) {$prologue +""" public $static$j_type$j_name($j_args) {$prologue $ret_val$jn_name($jn_args_call)$tail;$epilogue$ret } @@ -818,7 +855,7 @@ def gen_func(self, ci, fi, prop_name=''): prologue = "\n " + "\n ".join(j_prologue) if j_prologue else "", epilogue = "\n " + "\n ".join(j_epilogue) if j_epilogue else "", static = static + " " if static else "", - j_type=type_dict[fi.ctype]["j_type"], + j_type=type_dict[fi.ctype]["j_type"] + " " if type_dict[fi.ctype]["j_type"] else "", j_name=fi.jname, j_args=", ".join(j_args), jn_name=fi.jname + '_' + str(suffix_counter), @@ -1129,6 +1166,122 @@ def copy_java_files(java_files_dir, java_base_path, default_package_path='org/op copyfile(src, dest) updated_files += 1 +def sanitize_java_documentation_string(doc, type): + if type == "class": + doc = doc.replace("@param ", "") + + doc = re.sub(re.compile('\\\\f\\$(.*?)\\\\f\\$', re.DOTALL), '\\(' + r'\1' + '\\)', doc) + doc = re.sub(re.compile('\\\\f\\[(.*?)\\\\f\\]', re.DOTALL), '\\(' + r'\1' + '\\)', doc) + doc = re.sub(re.compile('\\\\f\\{(.*?)\\\\f\\}', re.DOTALL), '\\(' + r'\1' + '\\)', doc) + + doc = doc.replace("&", "&") \ + .replace("\\<", "<") \ + .replace("\\>", ">") \ + .replace("<", "<") \ + .replace(">", ">") \ + .replace("$", "$$") \ + .replace("@anchor", "") \ + .replace("@brief ", "").replace("\\brief ", "") \ + .replace("@cite", "CITE:") \ + .replace("@code{.cpp}", "") \ + .replace("@code{.txt}", "") \ + .replace("@code", "") \ + .replace("@copydoc", "") \ + .replace("@copybrief", "") \ + .replace("@date", "") \ + .replace("@defgroup", "") \ + .replace("@details ", "") \ + .replace("@endcode", "") \ + .replace("@endinternal", "") \ + .replace("@file", "") \ + .replace("@include", "INCLUDE:") \ + .replace("@ingroup", "") \ + .replace("@internal", "") \ + .replace("@overload", "") \ + .replace("@param[in]", "@param") \ + .replace("@param[out]", "@param") \ + .replace("@ref", "REF:") \ + .replace("@returns", "@return") \ + .replace("@sa", "SEE:") \ + .replace("@see", "SEE:") \ + .replace("@snippet", "SNIPPET:") \ + .replace("@todo", "TODO:") \ + .replace("@warning ", "WARNING: ") + + doc = re.sub(re.compile('\\*\\*([^\\*]+?)\\*\\*', re.DOTALL), '' + r'\1' + '', doc) + + lines = doc.splitlines() + + lines = list(map(lambda x: x[x.find('*'):].strip() if x.lstrip().startswith("*") else x, lines)) + + listInd = []; + indexDiff = 0; + for index, line in enumerate(lines[:]): + if line.strip().startswith("-"): + i = line.find("-") + if not listInd or i > listInd[-1]: + lines.insert(index + indexDiff, " "*len(listInd) + "

      ") + indexDiff += 1 + listInd.append(i); + lines.insert(index + indexDiff, " "*len(listInd) + "
    • ") + indexDiff += 1 + elif i == listInd[-1]: + lines.insert(index + indexDiff, " "*len(listInd) + "
    • ") + indexDiff += 1 + lines.insert(index + indexDiff, " "*len(listInd) + "
    • ") + indexDiff += 1 + elif len(listInd) > 1 and i == listInd[-2]: + lines.insert(index + indexDiff, " "*len(listInd) + "
    • ") + indexDiff += 1 + del listInd[-1] + lines.insert(index + indexDiff, " "*len(listInd) + "
    ") + indexDiff += 1 + lines.insert(index + indexDiff, " "*len(listInd) + "
  • ") + indexDiff += 1 + else: + lines.insert(index + indexDiff, " "*len(listInd) + "
  • ") + indexDiff += 1 + del listInd[-1] + lines.insert(index + indexDiff, " "*len(listInd) + "
") + indexDiff += 1 + lines.insert(index + indexDiff, " "*len(listInd) + "
    ") + indexDiff += 1 + listInd.append(i); + lines.insert(index + indexDiff, " "*len(listInd) + "
  • ") + indexDiff += 1 + lines[index + indexDiff] = lines[index + indexDiff][0:i] + lines[index + indexDiff][i + 1:] + else: + if listInd and (not line or line == "*" or line.startswith("@note")): + lines.insert(index + indexDiff, " "*len(listInd) + "
  • ") + indexDiff += 1 + del listInd[-1] + lines.insert(index + indexDiff, " "*len(listInd) + "
") + indexDiff += 1 + + i = len(listInd) - 1 + for value in enumerate(listInd): + lines.append(" "*i + " ") + lines.append(" "*i + "") + i -= 1; + + lines = list(map(lambda x: "* " + x[1:].strip() if x.startswith("*") and x != "*" else x, lines)) + lines = list(map(lambda x: x if x.startswith("*") else "* " + x if x and x != "*" else "*", lines)) + + lines = list(map(lambda x: x + .replace("@note", "Note:") + , lines)) + + lines = list(map(lambda x: re.sub('@b ([\\w:]+?)\\b', '' + r'\1' + '', x), lines)) + lines = list(map(lambda x: re.sub('@c ([\\w:]+?)\\b', '' + r'\1' + '', x), lines)) + lines = list(map(lambda x: re.sub('`(.*?)`', "{@code " + r'\1' + '}', x), lines)) + lines = list(map(lambda x: re.sub('@p ([\\w:]+?)\\b', '{@code ' + r'\1' + '}', x), lines)) + + hasValues = False + for line in lines: + if line != "*": + hasValues = True + break + return "/**\n " + "\n ".join(lines) + "\n */" if hasValues else "" if __name__ == "__main__": # initialize logger diff --git a/modules/java/generator/templates/java_class.prolog b/modules/java/generator/templates/java_class.prolog index 49404cb440b0..5662534bc5e0 100644 --- a/modules/java/generator/templates/java_class.prolog +++ b/modules/java/generator/templates/java_class.prolog @@ -5,8 +5,7 @@ package org.opencv.$module; $imports -$docs -$annotation +$docs$annotation public class $jname { protected final long nativeObj; diff --git a/modules/java/generator/templates/java_class_inherited.prolog b/modules/java/generator/templates/java_class_inherited.prolog index 17d5528a738a..5865afa1ad55 100644 --- a/modules/java/generator/templates/java_class_inherited.prolog +++ b/modules/java/generator/templates/java_class_inherited.prolog @@ -5,8 +5,7 @@ package org.opencv.$module; $imports -$docs -$annotation +$docs$annotation public class $jname extends $base { protected $jname(long addr) { super(addr); } diff --git a/modules/java/generator/templates/java_module.prolog b/modules/java/generator/templates/java_module.prolog index 41c453bd8cea..5ff6a83fd17c 100644 --- a/modules/java/generator/templates/java_module.prolog +++ b/modules/java/generator/templates/java_module.prolog @@ -5,6 +5,5 @@ package org.opencv.$module; $imports -$docs -$annotation +$docs$annotation public class $jname { diff --git a/modules/java/jar/build.xml.in b/modules/java/jar/build.xml.in index 41b55b76fc5b..28a428c4188d 100644 --- a/modules/java/jar/build.xml.in +++ b/modules/java/jar/build.xml.in @@ -29,6 +29,9 @@ + + + failonerror="true" + encoding="UTF-8" charset="UTF-8" docencoding="UTF-8" + link="https://docs.oracle.com/javase/6/docs/api/" + additionalparam="--allow-script-in-comments" + > +
+ + var url = window.location.href; + url = url.substring(0, url.lastIndexOf('/', url.indexOf('.html'))) + '/../../../mymath.js'; + var script = document.createElement('script'); + script.src = '@OPENCV_MATHJAX_RELPATH@/MathJax.js?config=TeX-AMS-MML_HTMLorMML,' + url; + document.getElementsByTagName('head')[0].appendChild(script); + + ]]> +
+
diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index eab88e0d6409..2dd35eb83736 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1004,7 +1004,7 @@ class CV_EXPORTS_W EM : public StatModel @param samples Samples from which the Gaussian mixture model will be estimated. It should be a one-channel matrix, each row of which is a sample. If the matrix does not have CV_64F type it will be converted to the inner matrix of such type for the further computing. - @param probs0 + @param probs0 the probabilities @param logLikelihoods The optional output matrix that contains a likelihood logarithm value for each sample. It has \f$nsamples \times 1\f$ size and CV_64FC1 type. @param labels The optional output "class label" for each sample: diff --git a/modules/python/src2/hdr_parser.py b/modules/python/src2/hdr_parser.py index 73b5ef4ed654..352ebe3d1f49 100755 --- a/modules/python/src2/hdr_parser.py +++ b/modules/python/src2/hdr_parser.py @@ -827,7 +827,7 @@ def parse(self, hname, wmode=True): if state == DOCSTRING: pos = l.find("*/") if pos < 0: - docstring += l + "\n" + docstring += l0 continue docstring += l[:pos] + "\n" l = l[pos+2:] diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index cc639d60a676..4228eab75991 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -803,8 +803,8 @@ class CV_EXPORTS_W VideoCapture @note Reading / writing properties involves many layers. Some unexpected result might happens along this chain. - @code {.txt} - `VideoCapture -> API Backend -> Operating System -> Device Driver -> Device Hardware` + @code{.txt} + VideoCapture -> API Backend -> Operating System -> Device Driver -> Device Hardware @endcode The returned value might be different from what really used by the device or it could be encoded using device dependent rules (eg. steps or percentage). Effective behaviour depends from device