#include "mat.h" using namespace Napi; #define MAT_INSTANCE_METHOD(method) InstanceMethod<&CVMat::method>(#method, static_cast(napi_writable | napi_configurable)) #define MAT_STATIC_METHOD(method) StaticMethod<&CVMat::method>(#method, static_cast(napi_writable | napi_configurable)) #define NODE_FUNCTION_IMPL(name) Napi::Value CVMat::name(const Napi::CallbackInfo &info) FunctionReference *CVMat::constructor = nullptr; Napi::Object CVMat::Init(Napi::Env env, Napi::Object exports) { Function func = DefineClass(env, "Mat", { MAT_STATIC_METHOD(ImRead), MAT_STATIC_METHOD(ImDecode), MAT_STATIC_METHOD(ImWrite), MAT_STATIC_METHOD(ImEncode), MAT_STATIC_METHOD(Crop), MAT_STATIC_METHOD(Resize), MAT_STATIC_METHOD(WarpAffine), MAT_STATIC_METHOD(Blur), MAT_STATIC_METHOD(CopyMakeBorder), MAT_STATIC_METHOD(Flip), MAT_STATIC_METHOD(GetRotationMatrix2D), MAT_STATIC_METHOD(Rectangle), MAT_STATIC_METHOD(Circle), MAT_STATIC_METHOD(Line), MAT_STATIC_METHOD(Ellipse), MAT_STATIC_METHOD(Polylines), MAT_STATIC_METHOD(FillPoly), MAT_STATIC_METHOD(FillConvexPoly), MAT_STATIC_METHOD(DrawMarker), MAT_STATIC_METHOD(PutText), MAT_INSTANCE_METHOD(IsEmpty), MAT_INSTANCE_METHOD(GetCols), MAT_INSTANCE_METHOD(GetRows), MAT_INSTANCE_METHOD(GetType), MAT_INSTANCE_METHOD(GetDepth), MAT_INSTANCE_METHOD(GetChannels), MAT_INSTANCE_METHOD(GetFlags), MAT_INSTANCE_METHOD(GetDims), MAT_INSTANCE_METHOD(GetIsContinuous), MAT_INSTANCE_METHOD(GetIsSubmatrix), MAT_INSTANCE_METHOD(GetElemSize), MAT_INSTANCE_METHOD(GetElemSize1), MAT_INSTANCE_METHOD(GetTotal), MAT_INSTANCE_METHOD(GetTotalWithDim), MAT_INSTANCE_METHOD(GetSize), MAT_INSTANCE_METHOD(GetData), MAT_INSTANCE_METHOD(Col), MAT_INSTANCE_METHOD(ColRange), MAT_INSTANCE_METHOD(Row), MAT_INSTANCE_METHOD(RowRange), MAT_INSTANCE_METHOD(Diag), MAT_INSTANCE_METHOD(Clone), MAT_INSTANCE_METHOD(CopyTo), }); constructor = new FunctionReference(); *constructor = Napi::Persistent(func); exports.Set("Mat", func); env.SetInstanceData(constructor); return exports; } CVMat::CVMat(const CallbackInfo &info) : ObjectWrap(info) { if (info.Length() >= 2) { auto sizesArray = info[0].As(); std::vector sizes(sizesArray.Length()); for (auto i = 0; i < sizes.size(); ++i) sizes[i] = sizesArray.Get(i).As().Int32Value(); auto type = info[1].As().Int32Value(); // 使用sizes和type初始化 if (info.Length() < 3) mat_ = cv::Mat(sizes, type); // 使用数据初始化 else if (info[2].IsTypedArray()) { auto dataArray = info[2].As(); auto data = static_cast(dataArray.ArrayBuffer().Data()) + dataArray.ByteOffset(); mat_ = cv::Mat(sizes, type, data); } // 其他 TODO else mat_ = cv::Mat(sizes, type); } } NODE_FUNCTION_IMPL(ImRead) { auto filename = info[0].As().Utf8Value(); int flag = (info.Length() >= 2) ? info[1].As().Int32Value() : cv::IMREAD_COLOR_BGR; return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = cv::imread(filename, flag); }); } NODE_FUNCTION_IMPL(ImDecode) { auto arr = info[0].As(); auto data = static_cast(arr.ArrayBuffer().Data()) + arr.ByteOffset(); std::vector buffer(data, data + arr.ByteLength()); int flag = (info.Length() >= 2) ? info[1].As().Int32Value() : cv::IMREAD_COLOR_BGR; return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = cv::imdecode(buffer, flag); }); } NODE_FUNCTION_IMPL(ImWrite) { auto &mat = GetMat(info[0].As()); auto filename = info[1].As().Utf8Value(); std::vector params; if (info[2].IsArray()) { auto paramArray = info[2].As(); params.resize(paramArray.Length()); for (auto i = 0; i < params.size(); ++i) params[i] = paramArray.Get(i).As().Int32Value(); } auto res = cv::imwrite(filename, mat.mat_, params); return Boolean::New(info.Env(), res); } NODE_FUNCTION_IMPL(ImEncode) { auto &mat = GetMat(info[0].As()); auto extname = info[1].As().Utf8Value(); std::vector params; if (info[2].IsArray()) { auto paramArray = info[2].As(); params.resize(paramArray.Length()); for (auto i = 0; i < params.size(); ++i) params[i] = paramArray.Get(i).As().Int32Value(); } std::vector buf; if (!cv::imencode(extname, mat.mat_, buf, params)) return info.Env().Undefined(); auto arrayBuffer = ArrayBuffer::New(info.Env(), buf.size()); auto bufferPtr = static_cast(arrayBuffer.Data()); for (auto ch : buf) { *bufferPtr = ch; bufferPtr++; } return arrayBuffer; } NODE_FUNCTION_IMPL(IsEmpty) { return Boolean::New(info.Env(), mat_.empty()); } NODE_FUNCTION_IMPL(GetCols) { return Number::New(info.Env(), mat_.cols); } NODE_FUNCTION_IMPL(GetRows) { return Number::New(info.Env(), mat_.rows); } NODE_FUNCTION_IMPL(GetType) { return Number::New(info.Env(), mat_.type()); } NODE_FUNCTION_IMPL(GetDepth) { return Number::New(info.Env(), mat_.depth()); } NODE_FUNCTION_IMPL(GetChannels) { return Number::New(info.Env(), mat_.channels()); } NODE_FUNCTION_IMPL(GetFlags) { return Number::New(info.Env(), mat_.flags); } NODE_FUNCTION_IMPL(GetDims) { return Number::New(info.Env(), mat_.dims); } NODE_FUNCTION_IMPL(GetIsContinuous) { return Boolean::New(info.Env(), mat_.isContinuous()); } NODE_FUNCTION_IMPL(GetIsSubmatrix) { return Boolean::New(info.Env(), mat_.isSubmatrix()); } NODE_FUNCTION_IMPL(GetElemSize) { return Number::New(info.Env(), static_cast(mat_.elemSize())); } NODE_FUNCTION_IMPL(GetElemSize1) { return Number::New(info.Env(), static_cast(mat_.elemSize1())); } NODE_FUNCTION_IMPL(GetTotal) { return Number::New(info.Env(), static_cast(mat_.total())); } NODE_FUNCTION_IMPL(GetTotalWithDim) { return Number::New(info.Env(), static_cast(mat_.total(info[0].As().Int32Value(), info[1].As().Int32Value()))); } NODE_FUNCTION_IMPL(GetSize) { auto ret = Array::New(info.Env(), mat_.dims); auto &size = mat_.size; for (int i = 0; i < mat_.dims; ++i) ret.Set(i, size[i]); return ret; } NODE_FUNCTION_IMPL(GetData) { auto ptr = mat_.ptr(); auto bytes = mat_.elemSize() * mat_.total(); return ArrayBuffer::New(info.Env(), ptr, bytes); } NODE_FUNCTION_IMPL(Col) { auto col = info[0].As().Int32Value(); return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.col(col); }); } NODE_FUNCTION_IMPL(ColRange) { auto start = info[0].As().Int32Value(); auto end = info[1].As().Int32Value(); return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.colRange(start, end); }); } NODE_FUNCTION_IMPL(Row) { auto row = info[0].As().Int32Value(); return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.row(row); }); } NODE_FUNCTION_IMPL(RowRange) { auto start = info[0].As().Int32Value(); auto end = info[1].As().Int32Value(); return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.rowRange(start, end); }); } NODE_FUNCTION_IMPL(Diag) { auto d = info[0].As().Int32Value(); return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.diag(d); }); } NODE_FUNCTION_IMPL(Clone) { return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.clone(); }); } NODE_FUNCTION_IMPL(CopyTo) { auto &target = GetMat(info[0].As()); mat_.copyTo(target.mat_); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(Crop) { auto &src = GetMat(info[0].As()); auto &dst = GetMat(info[1].As()); auto rangeArray = info[2].As(); std::vector ranges(rangeArray.Length()); for (int i = 0; i < ranges.size(); ++i) { auto item = rangeArray.Get(i).As(); auto start = item.Get("start").As().Int32Value(); auto end = item.Get("end").As().Int32Value(); ranges[i] = cv::Range(start, end); } dst.mat_ = src.mat_(ranges); return info[1]; } NODE_FUNCTION_IMPL(Resize) { auto &src = GetMat(info[0].As()); auto &dst = GetMat(info[1].As()); auto width = info[2].As().Int32Value(); auto height = info[3].As().Int32Value(); auto fx = info[4].As().DoubleValue(); auto fy = info[5].As().DoubleValue(); auto interpolation = info[6].As().Int32Value(); cv::resize(src.mat_, dst.mat_, cv::Size(width, height), fx, fy, interpolation); return info[1]; } NODE_FUNCTION_IMPL(WarpAffine) { auto &src = GetMat(info[0].As()); auto &dst = GetMat(info[1].As()); auto &transformMat = GetMat(info[2].As()); auto dwidth = info[3].As().Int32Value(); auto dheight = info[4].As().Int32Value(); auto flags = info[5].As().Int32Value(); auto borderMode = info[6].As().Int32Value(); cv::warpAffine(src.mat_, dst.mat_, transformMat.mat_, cv::Size(dwidth, dheight), flags, borderMode); return info[1]; } NODE_FUNCTION_IMPL(Blur) { auto &src = GetMat(info[0].As()); auto &dst = GetMat(info[1].As()); auto kwidth = info[2].As().Int32Value(); auto kheight = info[3].As().Int32Value(); auto anchorX = info[4].As().Int32Value(); auto anchorY = info[5].As().Int32Value(); auto borderType = info[6].As().Int32Value(); cv::blur(src.mat_, dst.mat_, cv::Size(kwidth, kheight), cv::Point(anchorX, anchorY), borderType); return info[1]; } NODE_FUNCTION_IMPL(CopyMakeBorder) { auto &src = GetMat(info[0].As()); auto &dst = GetMat(info[1].As()); auto top = info[2].As().Int32Value(); auto bottom = info[3].As().Int32Value(); auto left = info[4].As().Int32Value(); auto right = info[5].As().Int32Value(); auto borderType = info[6].As().Int32Value(); cv::copyMakeBorder(src.mat_, dst.mat_, top, bottom, left, right, borderType); return info[1]; } NODE_FUNCTION_IMPL(Flip) { auto &src = GetMat(info[0].As()); auto &dst = GetMat(info[1].As()); auto flipCode = info[2].As().Int32Value(); cv::flip(src.mat_, dst.mat_, flipCode); return info[1]; } NODE_FUNCTION_IMPL(GetRotationMatrix2D) { auto centerX = info[0].As().FloatValue(); auto centerY = info[1].As().FloatValue(); auto angle = info[2].As().DoubleValue(); auto scale = info[3].As().DoubleValue(); return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = cv::getRotationMatrix2D(cv::Point2f(centerX, centerY), angle, scale); }); } NODE_FUNCTION_IMPL(Rectangle) { auto &img = GetMat(info[0].As()); auto x1 = info[1].As().Int32Value(); auto y1 = info[2].As().Int32Value(); auto x2 = info[3].As().Int32Value(); auto y2 = info[4].As().Int32Value(); auto b = info[5].As().DoubleValue(); auto g = info[6].As().DoubleValue(); auto r = info[7].As().DoubleValue(); auto thickness = info[8].As().Int32Value(); auto lineType = info[9].As().Int32Value(); auto shift = info[10].As().Int32Value(); cv::rectangle(img.mat_, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(b, g, r), thickness, lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(Circle) { auto &img = GetMat(info[0].As()); auto x = info[1].As().Int32Value(); auto y = info[2].As().Int32Value(); auto radius = info[3].As().Int32Value(); auto b = info[4].As().DoubleValue(); auto g = info[5].As().DoubleValue(); auto r = info[6].As().DoubleValue(); auto thickness = info[7].As().Int32Value(); auto lineType = info[8].As().Int32Value(); auto shift = info[9].As().Int32Value(); cv::circle(img.mat_, cv::Point(x, y), radius, cv::Scalar(b, g, r), thickness, lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(Line) { auto &img = GetMat(info[0].As()); auto x1 = info[1].As().Int32Value(); auto y1 = info[2].As().Int32Value(); auto x2 = info[3].As().Int32Value(); auto y2 = info[4].As().Int32Value(); auto b = info[5].As().DoubleValue(); auto g = info[6].As().DoubleValue(); auto r = info[7].As().DoubleValue(); auto thickness = info[8].As().Int32Value(); auto lineType = info[9].As().Int32Value(); auto shift = info[10].As().Int32Value(); cv::line(img.mat_, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(b, g, r), thickness, lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(Ellipse) { auto &img = GetMat(info[0].As()); auto x = info[1].As().Int32Value(); auto y = info[2].As().Int32Value(); auto width = info[3].As().Int32Value(); auto height = info[4].As().Int32Value(); auto angle = info[5].As().DoubleValue(); auto startAngle = info[6].As().DoubleValue(); auto endAngle = info[7].As().DoubleValue(); auto b = info[8].As().DoubleValue(); auto g = info[9].As().DoubleValue(); auto r = info[10].As().DoubleValue(); auto thickness = info[11].As().Int32Value(); auto lineType = info[12].As().Int32Value(); auto shift = info[13].As().Int32Value(); cv::ellipse(img.mat_, cv::Point(x, y), cv::Size(width, height), angle, startAngle, endAngle, cv::Scalar(b, g, r), thickness, lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(Polylines) { auto &img = GetMat(info[0].As()); auto points_ = info[1].As(); std::vector points(points_.Length()); for (uint32_t i = 0; i < points_.Length(); i++) { auto pt = points_.Get(i).As(); points[i] = cv::Point(pt.Get(0U).As().Int32Value(), pt.Get(1U).As().Int32Value()); } auto isClosed = info[2].As().Value(); auto b = info[3].As().DoubleValue(); auto g = info[4].As().DoubleValue(); auto r = info[5].As().DoubleValue(); auto thickness = info[6].As().Int32Value(); auto lineType = info[7].As().Int32Value(); auto shift = info[8].As().Int32Value(); cv::polylines(img.mat_, points, isClosed, cv::Scalar(b, g, r), thickness, lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(FillPoly) { auto &img = GetMat(info[0].As()); auto points_ = info[1].As(); std::vector points(points_.Length()); for (uint32_t i = 0; i < points_.Length(); i++) { auto pt = points_.Get(i).As(); points[i] = cv::Point(pt.Get(0U).As().Int32Value(), pt.Get(1U).As().Int32Value()); } auto b = info[2].As().DoubleValue(); auto g = info[3].As().DoubleValue(); auto r = info[4].As().DoubleValue(); auto lineType = info[5].As().Int32Value(); auto shift = info[6].As().Int32Value(); cv::fillPoly(img.mat_, points, cv::Scalar(b, g, r), lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(FillConvexPoly) { auto &img = GetMat(info[0].As()); auto points_ = info[1].As(); std::vector points(points_.Length()); for (uint32_t i = 0; i < points_.Length(); i++) { auto pt = points_.Get(i).As(); points[i] = cv::Point(pt.Get(0U).As().Int32Value(), pt.Get(1U).As().Int32Value()); } auto b = info[2].As().DoubleValue(); auto g = info[3].As().DoubleValue(); auto r = info[4].As().DoubleValue(); auto lineType = info[5].As().Int32Value(); auto shift = info[6].As().Int32Value(); cv::fillConvexPoly(img.mat_, points, cv::Scalar(b, g, r), lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(DrawMarker) { auto &img = GetMat(info[0].As()); auto x = info[1].As().Int32Value(); auto y = info[2].As().Int32Value(); auto b = info[3].As().DoubleValue(); auto g = info[4].As().DoubleValue(); auto r = info[5].As().DoubleValue(); auto markerType = info[6].As().Int32Value(); auto markerSize = info[7].As().Int32Value(); auto lineType = info[8].As().Int32Value(); auto shift = info[9].As().Int32Value(); cv::drawMarker(img.mat_, cv::Point(x, y), cv::Scalar(b, g, r), markerType, markerSize, lineType, shift); return info.Env().Undefined(); } NODE_FUNCTION_IMPL(PutText) { auto &img = GetMat(info[0].As()); auto text = info[1].As().Utf8Value(); auto x = info[2].As().Int32Value(); auto y = info[3].As().Int32Value(); auto fontFace = info[4].As().Int32Value(); auto fontScale = info[5].As().DoubleValue(); auto b = info[6].As().DoubleValue(); auto g = info[7].As().DoubleValue(); auto r = info[8].As().DoubleValue(); auto thickness = info[9].As().Int32Value(); auto lineType = info[10].As().Int32Value(); auto shift = info[11].As().Int32Value(); auto bottomLeftOrigin = info[12].As().Value(); cv::putText(img.mat_, text, cv::Point(x, y), fontFace, fontScale, cv::Scalar(b, g, r), thickness, lineType, bottomLeftOrigin); return info.Env().Undefined(); } void InitMatAPI(Napi::Env env, Napi::Object exports) { CVMat::Init(env, exports); }