1
+ # Contribution Guide
2
+
1
3
First of all, any kind of contribution is highly appreciated, you don't have to be a pro in C++, neither am I. If you are totally new to native Node.js development and would like to get started, you can have a look at my article series as a quick introduction:
2
4
<a href =" https://medium.com/netscape/tutorial-building-native-c-modules-for-node-js-using-nan-part-1-755b07389c7c " ><b >Tutorial to Native Node.js Modules with C++</b ></a >
3
5
4
-
5
6
Oftentimes adding bindings is done similarly to what already exists in the codebase. Thus, you can take the existing stuff as an example to help you to get started. In the following, you can find some basic guidelines for adding new OpenCV function bindings to the package.
6
7
7
8
## API Design
9
+
8
10
The API is designed such that
9
11
10
12
A: Parameters passed to a function call are type checked and appropriate messages are displayed to the user in case an error occured. Nobody wants passing garbage to a function by coincidence to fail silently, which may produce unexpected results.
@@ -16,6 +18,7 @@ void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, do
16
18
```
17
19
18
20
The function should be invokable in the following ways:
21
+
19
22
``` javascript
20
23
const mat = new cv.Mat(...)
21
24
@@ -53,11 +56,11 @@ In the .h file add the declaration of the bindings its' worker to the class defi
53
56
``` c++
54
57
class Mat : public Nan ::ObjectWrap {
55
58
56
- ...
59
+ ...
57
60
58
- struct GaussianBlurWorker;
59
- NAN_METHOD(GaussianBlur);
60
- NAN_METHOD(GaussianBlurAsync);
61
+ struct GaussianBlurWorker;
62
+ NAN_METHOD(GaussianBlur);
63
+ NAN_METHOD(GaussianBlurAsync);
61
64
62
65
}
63
66
@@ -69,81 +72,81 @@ In the .cc file add the implementation of the worker:
69
72
struct Mat::GaussianBlurWorker : public SimpleWorker {
70
73
public:
71
74
// instance of the class exposing the method
72
- cv::Mat mat;
73
- GaussianBlurWorker(cv::Mat mat) {
74
- this->mat = mat;
75
- }
75
+ cv::Mat mat;
76
+ GaussianBlurWorker(cv::Mat mat) {
77
+ this->mat = mat;
78
+ }
76
79
77
80
// required function arguments
78
- cv::Size2d kSize;
79
- double sigmaX;
81
+ cv::Size2d kSize;
82
+ double sigmaX;
80
83
// optional function arguments
81
- double sigmaY = 0;
82
- int borderType = cv::BORDER_CONSTANT;
84
+ double sigmaY = 0;
85
+ int borderType = cv::BORDER_CONSTANT;
83
86
84
87
// function return value
85
- cv::Mat blurMat;
88
+ cv::Mat blurMat;
86
89
87
90
// here the main work is performed, the async worker will execute
88
91
// this in a different thread
89
- const char* execute() {
90
- cv::GaussianBlur(mat, blurMat, kSize, sigmaX, sigmaY, borderType);
92
+ const char* execute() {
93
+ cv::GaussianBlur(mat, blurMat, kSize, sigmaX, sigmaY, borderType);
91
94
// if you need to handle errors, you can return an error message here, which
92
95
// will trigger the error callback if message is not empty
93
- return "";
94
- }
96
+ return "";
97
+ }
95
98
96
99
// return the native objects, handle all object wrapping stuff here
97
- v8::Local<v8::Value> getReturnValue() {
98
- return Mat::Converter::wrap(blurMat);
99
- }
100
-
101
- // implement this method if function takes any required arguments
102
- bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
103
- return (
104
- Size::Converter::arg(0, &kSize, info) ||
105
- DoubleConverter::arg(1, &sigmaX, info)
106
- );
107
- }
108
-
109
- // implement this method if function takes any optional arguments
110
- bool unwrapOptionalArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
111
- return (
112
- DoubleConverter::optArg(2, &sigmaY, info) ||
113
- IntConverter::optArg(3, &borderType, info)
114
- );
115
- }
116
-
117
- // implement the following methods if function takes more than a single optional parameter
118
-
119
- // check if a JSON object as the first argument after the required arguments
120
- bool hasOptArgsObject(Nan::NAN_METHOD_ARGS_TYPE info) {
121
- return FF_ARG_IS_OBJECT(2);
122
- }
123
-
124
- // get the values from named properties of the JSON object
125
- bool unwrapOptionalArgsFromOpts(Nan::NAN_METHOD_ARGS_TYPE info) {
126
- FF_OBJ opts = info[2]->ToObject();
127
- return (
128
- DoubleConverter::optProp(&sigmaY, "sigmaY", opts) ||
129
- IntConverter::optProp(&borderType, "borderType", opts)
130
- );
131
- }
100
+ v8::Local<v8::Value> getReturnValue() {
101
+ return Mat::Converter::wrap(blurMat);
102
+ }
103
+
104
+ // implement this method if function takes any required arguments
105
+ bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
106
+ return (
107
+ Size::Converter::arg(0, &kSize, info) ||
108
+ DoubleConverter::arg(1, &sigmaX, info)
109
+ );
110
+ }
111
+
112
+ // implement this method if function takes any optional arguments
113
+ bool unwrapOptionalArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
114
+ return (
115
+ DoubleConverter::optArg(2, &sigmaY, info) ||
116
+ IntConverter::optArg(3, &borderType, info)
117
+ );
118
+ }
119
+
120
+ // implement the following methods if function takes more than a single optional parameter
121
+
122
+ // check if a JSON object as the first argument after the required arguments
123
+ bool hasOptArgsObject(Nan::NAN_METHOD_ARGS_TYPE info) {
124
+ return FF_ARG_IS_OBJECT(2);
125
+ }
126
+
127
+ // get the values from named properties of the JSON object
128
+ bool unwrapOptionalArgsFromOpts(Nan::NAN_METHOD_ARGS_TYPE info) {
129
+ FF_OBJ opts = info[2]->ToObject();
130
+ return (
131
+ DoubleConverter::optProp(&sigmaY, "sigmaY", opts) ||
132
+ IntConverter::optProp(&borderType, "borderType", opts)
133
+ );
134
+ }
132
135
};
133
136
```
134
137
135
138
After you have set up the worker, implementing the bindings is as easy as follows:
136
139
137
140
``` c++
138
141
NAN_METHOD (Mat::GaussianBlur) {
139
- GaussianBlurWorker worker(Mat::Converter::unwrap(info.This()));
140
- FF_WORKER_SYNC("Mat::GaussianBlur", worker);
141
- info.GetReturnValue().Set(worker.getReturnValue());
142
+ GaussianBlurWorker worker(Mat::Converter::unwrap(info.This()));
143
+ FF_WORKER_SYNC("Mat::GaussianBlur", worker);
144
+ info.GetReturnValue().Set(worker.getReturnValue());
142
145
}
143
146
144
147
NAN_METHOD(Mat::GaussianBlurAsync) {
145
- GaussianBlurWorker worker(Mat::Converter::unwrap(info.This()));
146
- FF_WORKER_ASYNC("Mat::GaussianBlurAsync", GaussianBlurWorker, worker);
148
+ GaussianBlurWorker worker(Mat::Converter::unwrap(info.This()));
149
+ FF_WORKER_ASYNC("Mat::GaussianBlurAsync", GaussianBlurWorker, worker);
147
150
}
148
151
```
149
152
@@ -152,6 +155,7 @@ NAN_METHOD(Mat::GaussianBlurAsync) {
152
155
For converting native types to v8 types and unwrapping/ wrapping objects and instances you can use the Converters. A Converter will perform type checking and throw an error if converting a value or unwrapping an object failed. If a converter returns true, an error was thrown. You should use the Converters in conjunction with a worker struct. Otherwise you will have to handle rethrowing the error manually. There are Converters for conversion of primitive types, for unwrapping/ wrapping class instances as well as arrays of primitive types and arrays of instances. For representation of a JS array in c++ we are using std::vector.
153
156
154
157
Some Usage examples:
158
+
155
159
``` c++
156
160
// require arg 0 to be a Mat
157
161
cv::Mat img;
@@ -191,25 +195,25 @@ v8::Local<v8::Array> jsPoints = ObjectArrayConverter<Point2, cv::Point2d>::wrap(
191
195
// std::vector<cv::Point2i> you can use the third template parameter to specify a conversion type
192
196
std::vector<cv::Point2i> points;
193
197
v8::Local<v8::Array> jsPoints = ObjectArrayConverter<Point2, cv::Point2d, cv::Point2i>::wrap(points);
194
- ObjectArrayConverter<Point2, cv::Point2d, cv::Point2i>::wrap(points);
195
198
```
196
199
197
200
A class can be made convertable if you you add the typedef for an InstanceConverter the class definition. Example for the Mat class wrapper:
201
+
198
202
``` c++
199
203
class Mat : public Nan ::ObjectWrap {
200
204
public:
201
205
cv::Mat mat;
202
206
203
- ...
207
+ ...
204
208
205
- cv::Mat* getNativeObjectPtr() { return &mat; }
206
- cv::Mat getNativeObject () { return mat; }
209
+ cv::Mat* getNativeObjectPtr() { return &mat; }
210
+ cv::Mat getNativeObject() { return mat; }
207
211
208
- typedef InstanceConverter<Mat, cv::Mat> Converter;
212
+ typedef InstanceConverter<Mat, cv::Mat> Converter;
209
213
210
- static const char* getClassName() {
211
- return "Mat";
212
- }
214
+ static const char* getClassName() {
215
+ return "Mat";
216
+ }
213
217
};
214
218
```
215
219
@@ -272,13 +276,15 @@ In the corresponding markdown file in the doc folder add some docs, so that peop
272
276
<a name="gaussianBlur"></a >
273
277
274
278
### gaussianBlur
279
+
275
280
``` javascript
276
281
Mat : mat .gaussianBlur (Size kSize, Number sigmaX, Number sigmaY = 0.0 , Uint borderType = BORDER_CONSTANT )
277
282
```
278
283
279
284
<a name="gaussianBlurAsync"></a >
280
285
281
286
### gaussianBlurAsync
287
+
282
288
``` javascript
283
289
mat .gaussianBlurAsync (Size kSize, Number sigmaX, callback (Error err, Mat result))
284
290
mat .gaussianBlurAsync (Size kSize, Number sigmaX, ... opts, callback (Error err, Mat result))
0 commit comments