#include #include #include #include "node.h" using namespace Napi; #define MAT_INSTANCE_METHOD(method) InstanceMethod<&CVMat::method>(#method, static_cast(napi_writable | napi_configurable)) static FunctionReference *constructor = nullptr; class CVMat : public ObjectWrap { public: static Napi::Object Init(Napi::Env env, Napi::Object exports) { Function func = DefineClass(env, "Mat", { MAT_INSTANCE_METHOD(IsEmpty), MAT_INSTANCE_METHOD(GetCols), MAT_INSTANCE_METHOD(GetRows), MAT_INSTANCE_METHOD(GetChannels), MAT_INSTANCE_METHOD(Resize), MAT_INSTANCE_METHOD(Crop), MAT_INSTANCE_METHOD(Rotate), MAT_INSTANCE_METHOD(Clone), MAT_INSTANCE_METHOD(DrawCircle), MAT_INSTANCE_METHOD(Data), MAT_INSTANCE_METHOD(Encode), }); constructor = new FunctionReference(); *constructor = Napi::Persistent(func); exports.Set("Mat", func); env.SetInstanceData(constructor); return exports; } CVMat(const CallbackInfo &info) : ObjectWrap(info) { int mode = cv::IMREAD_COLOR_BGR; if (info.Length() > 1 && info[1].IsObject()) { Object options = info[1].As(); if (options.Has("mode") && options.Get("mode").IsNumber()) mode = options.Get("mode").As().Int32Value(); } if (info[0].IsString()) im_ = cv::imread(info[0].As().Utf8Value(), mode); else if (info[0].IsTypedArray()) { auto buffer = info[0].As().ArrayBuffer(); uint8_t *bufferPtr = static_cast(buffer.Data()); std::vector data(bufferPtr, bufferPtr + buffer.ByteLength()); im_ = cv::imdecode(data, mode); } } ~CVMat() { im_.release(); } Napi::Value IsEmpty(const Napi::CallbackInfo &info) { return Boolean::New(info.Env(), im_.empty()); } Napi::Value GetCols(const Napi::CallbackInfo &info) { return Number::New(info.Env(), im_.cols); } Napi::Value GetRows(const Napi::CallbackInfo &info) { return Number::New(info.Env(), im_.rows); } Napi::Value GetChannels(const Napi::CallbackInfo &info) { return Number::New(info.Env(), im_.channels()); } Napi::Value Resize(const Napi::CallbackInfo &info) { return CreateMat(info.Env(), [this, &info](auto &mat) { cv::resize(im_, mat.im_, cv::Size(info[0].As().Int32Value(), info[1].As().Int32Value())); }); } Napi::Value Crop(const Napi::CallbackInfo &info) { return CreateMat(info.Env(), [this, &info](auto &mat) { mat.im_ = im_(cv::Rect( info[0].As().Int32Value(), info[1].As().Int32Value(), info[2].As().Int32Value(), info[3].As().Int32Value())); }); } Napi::Value Rotate(const Napi::CallbackInfo &info) { return CreateMat(info.Env(), [this, &info](auto &mat) { auto x = info[0].As().DoubleValue(); auto y = info[1].As().DoubleValue(); auto angle = info[2].As().DoubleValue(); cv::Mat rotation_matix = cv::getRotationMatrix2D(cv::Point2f(x, y), angle, 1.0); cv::warpAffine(im_, mat.im_, rotation_matix, im_.size()); }); } Napi::Value Clone(const Napi::CallbackInfo &info) { return CreateMat(info.Env(), [this, &info](auto &mat) { mat.im_ = im_.clone(); }); } Napi::Value DrawCircle(const Napi::CallbackInfo &info) { int x = info[0].As().Int32Value(); int y = info[1].As().Int32Value(); int radius = info[2].As().Int32Value(); int b = info[3].As().Int32Value(); int g = info[4].As().Int32Value(); int r = info[5].As().Int32Value(); int thickness = info[6].As().Int32Value(); int lineType = info[7].As().Int32Value(); int shift = info[8].As().Int32Value(); cv::circle(im_, cv::Point(x, y), radius, cv::Scalar(b, g, r), thickness, lineType, shift); return info.Env().Undefined(); } Napi::Value Data(const Napi::CallbackInfo &info) { return ArrayBuffer::New(info.Env(), im_.ptr(), im_.elemSize() * im_.total()); } Napi::Value Encode(const Napi::CallbackInfo &info) { auto options = info[0].As(); auto extname = options.Get("extname").As().Utf8Value(); cv::imencode(extname, im_, encoded_); return ArrayBuffer::New(info.Env(), encoded_.data(), encoded_.size()); } private: inline Napi::Object EmptyMat(Napi::Env env) { return constructor->New({}).As(); } inline CVMat &GetMat(Napi::Object obj) { return *ObjectWrap::Unwrap(obj); } inline Napi::Object CreateMat(Napi::Env env, std::function callback) { auto obj = EmptyMat(env); callback(GetMat(obj)); return obj; } private: cv::Mat im_; std::vector encoded_; }; void InstallOpenCVAPI(Env env, Object exports) { CVMat::Init(env, exports); } #ifdef USE_OPENCV static Object Init(Env env, Object exports) { InstallOpenCVAPI(env, exports); return exports; } NODE_API_MODULE(addon, Init) #endif