C++ Addon Async 异步机制

线程队列: libuv,window 可在libuv官网下载相应版本

opencv:  编译的时候opencv的位数要和 node的bit 一致

兼容electron :  node-gyp rebuild --version   --Debug/--Release  --archs=x64/ia32  

 v8文档: https://v8docs.nodesource.com/

#include <node.h>
#include <v8.h>
#include <uv.h>
#include <windows.h>
#include <string.h>
#include <string>
#include <iostream>
#include <thread>
#include <opencv/cv.h>
#include <opencv2/opencv.hpp>



using namespace v8;
// 传入了两个参数,args[0] 字符串,args[1] 回调函数s
struct SImageData {
    int status = -1;
    int width = 0;
    int height = 0;
    int channels = 0;
    int size = 0;
    int step = 0;
    std::vector<int> data;
    std::string msg; //msg
};


void hello(const FunctionCallbackInfo<Value>& args) {
  // 使用 HandleScope 来管理生命周期s
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  // 判断参数格式和格式s
  if (args.Length() < 2 || !args[0]->IsString()) {
    isolate->ThrowException(Exception::TypeError(
      String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }

  // callback, 使用Cast方法来转换s
  Local<Function> callback = Local<Function>::Cast(args[1]);
  Local<Value> argv[1] = {
    // 拼接String
    String::Concat(Local<String>::Cast(args[0]), String::NewFromUtf8(isolate, " world"))
  };
  // 调用回调, 参数: 当前上下文,参数个数,参数列表s
  callback->Call(isolate->GetCurrentContext()->Global(), 1, argv);
}
//三个参数  图片路径,目标图片宽度, 返回值: 图像参数,数据流s
void getImageData(const FunctionCallbackInfo<Value>& args){
    Isolate* isolate = args.GetIsolate();

    SImageData sData;
    // 参数长度判断s
    /*
    if (args.Length() < 3) {
     isolate->ThrowException(Exception::TypeError(
         String::NewFromUtf8(isolate, "Wrong params of arguments")));
         return ;
    }
    */
    // js String 类型转换成 v8 String 类型s
    Local<String> filepath = Local<String>::Cast(args[0]);
    String::Utf8Value filePath(filepath);
    // js Number 类型转换成 v8 Number 类型s
    Local<Number> dstWidth = Local<Number>::Cast(args[1]);
    printf("%s %f\n", *filePath, dstWidth->NumberValue());


    cv::Mat srcImg = cv::imread(std::string(*filePath));
    cv::Mat img;
    int width = srcImg.cols;
    int height = srcImg.rows;
     //图片压缩s
    int r_width = width;
    int r_height = r_width * height / width;

    resize(srcImg, img, cv::Size(r_width, r_height), 0, 0, 3);
    // 获取图片流信息
    int channels = img.channels();
    uchar* buffer = img.data;
    width = img.cols;
    height = img.rows;
    //printf("width = %d\n;height = %d\n;channels = %d\n;step = %d\n",width, height, channels, step);
    int size = width * channels * height;
    sData.data.clear();
    /*
    for (int i = 0; i < size; i += channels) {
        int r = buffer[i];
        int g = buffer[i + 1];
        int b = buffer[i + 2];
        sData.data.push_back(r);
        sData.data.push_back(g);
        sData.data.push_back(b);
    }
    */
    sData.status = 1;
    sData.width = img.cols;
    sData.height = img.rows;
    sData.size = size;
    sData.step = img.step;
    sData.channels = channels;

     //c++ -> js
    Local<Object> obj = Object::New(isolate);
    // Number type
    Local<Number> jsStatus = Number::New(isolate, sData.status);
    Local<Number> jsWidth = Number::New(isolate, sData.width);
    Local<Number> jsHeight = Number::New(isolate, sData.height);
    Local<Number> jsSize = Number::New(isolate, sData.size);
    Local<Number> jsStep = Number::New(isolate, sData.step);
    Local<Number> jsChannels = Number::New(isolate, sData.channels);

    obj->Set(String::NewFromUtf8(isolate, "status"), jsStatus);
    obj->Set(String::NewFromUtf8(isolate, "width"), jsWidth);
    obj->Set(String::NewFromUtf8(isolate, "height"), jsHeight);
    obj->Set(String::NewFromUtf8(isolate, "size"), jsSize);
    obj->Set(String::NewFromUtf8(isolate, "step"), jsStep);
    obj->Set(String::NewFromUtf8(isolate, "channels"), jsChannels);

    //args.GetReturnValue().Set(obj);
    // callback, 使用Cast方法来转换s
    Local<Function> callback = Local<Function>::Cast(args[2]);
    const unsigned argc = 1;
    Local<Value> argv[argc] = { obj };
    //cb->Call(Null(isolate), argc, argv);
      // 调用回调, 参数: 当前上下文,参数个数,参数列表s
    callback->Call(isolate->GetCurrentContext()->Global(), argc, argv);
}
//async
//在AddOn中,定义一个结构体在异步调用中传递数据s
struct LookupIpCountryBaton {
    uv_work_t work;              //libuv
    Persistent<Function> callback;    //javascript callback  <heap>

    int type;
};

void lookupIpCountryAsync(uv_work_t * work){
    LookupIpCountryBaton * baton = (LookupIpCountryBaton*)work->data;

    // block thread for 3 seconds
    Sleep(3000);
    // save the result
    baton->type = 100002;
}

void lookupIpCountryCompleted(uv_work_t * work, int){
    LookupIpCountryBaton * baton = (LookupIpCountryBaton*)work->data;
    Isolate * isolate = Isolate::GetCurrent();
    HandleScope handleScope(isolate);
    const unsigned argc = 1;
    Local<Value> argv[argc] = {String::NewFromUtf8(isolate, "HHEE")};
    Local<Function>::New(isolate, baton->callback)->Call(isolate->GetCurrentContext()->Global(), argc, argv);

    baton->callback.Reset();
    delete baton;

}
//导出方法首先保存回调函数,并验证和解析传入参数s
// lookup country by ip
// 1st argument is ip address
// 2nd argument is the callback function
void lookupIpCountry(const FunctionCallbackInfo<Value>& args) {
    Isolate *isolate = args.GetIsolate();
    Local<Context> context = isolate->GetCurrentContext();
    HandleScope scope(isolate);
    if (args.Length() < 2) {
        isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong params of arguments")));
        return ;
    }

    LookupIpCountryBaton * baton = new LookupIpCountryBaton();
    baton->work.data = baton;
    baton->type = 200;

    //baton->callback = Persistent<Function>::New(Handle<Function>::Cast(args[1]));
    baton->callback.Reset(isolate, Local<Function>::Cast(args[1]));


    uv_queue_work( uv_default_loop(), &baton->work, lookupIpCountryAsync, lookupIpCountryCompleted);

    return ;
}

// 相当于在 exports 对象中添加 { hello: hello }
void init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, "hello", hello);
  NODE_SET_METHOD(exports, "getImageData", getImageData);
  NODE_SET_METHOD(exports, "delay", lookupIpCountry);
}

// 将 export 对象暴露出去s
// 原型 `NODE_MODULE(module_name, Initialize)`s
NODE_MODULE(opencv_image, init);

 

posted @ 2018-11-08 18:07  一样菜  阅读(892)  评论(0编辑  收藏  举报