4

I want to use a C-Function from Node.js by using N-API with node-addon-api module wrapper. This is the first time with N-API for me and I'm also a beginner with Node and C++. I have a experience in C programming of embedded systems but this Node.jS / N-API thing I don't understand completely yet...

What I wan't to do is to call a C-Function with this prototype from Node.js:

unsigned char *MyFunction(unsigned char *data, size_t size, size_t min, size_t max)

*data is a pointer to an array containing RGB image data [R0, G0, B0, R1, G1, B1, ...] with size size which should be processed in MyFunction (extracting RGB channels, inverting, ...).

What I have so far is this c++ code:

#include <napi.h>

using namespace Napi;

Napi::Value Method(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  if (info.Length() != 3) {
    Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
    return env.Null();    
  }
  else {
    const Napi::Array inputArray = info[0].As<Napi::Array>();
    const float smin = info[1].As<Napi::Number>().FloatValue();
    const float smax = info[2].As<Napi::Number>().FloatValue();
    const unsigned int length = inputArray.Length();
    unsigned int i;
    Napi::Array outputArray = Napi::Array::New(env, length);
    Napi::Array redArray = Napi::Array::New(env, length / 3);
    Napi::Array greenArray = Napi::Array::New(env, length / 3);
    Napi::Array blueArray = Napi::Array::New(env, length / 3);

    // Extract Channels
    for (i = 0; i < (length / 3); i++) {
      redArray[i] = inputArray[i * 3];
      greenArray[i] = inputArray[i * 3 + 1];
      blueArray[i] = inputArray[i * 3 + 2];
    }

    // Apply Simple Color Balance to each channel
    for (i = 0; i < (length / 3); i++) {
      outputArray[i] = redArray[i];
    }
    return redArray;    // Test => this works
  }
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "Test"),
              Napi::Function::New(env, Method));
  return exports;
}

NODE_API_MODULE(module, Init)

and this is the node part:

const  sharp  = require('sharp');
sharp('testPic.jpg')
  .resize(800, 600)
  .toFile('SharpOut.jpg')
  .then( data => { 
    console.log('Resize & Negate => OK')
    // Extract Channel data
    sharp('SharpOut.jpg')
    .raw()
    .toBuffer()
    .then(data => {
      var smin = 0.0;
      var smax = 0.0;
      var testArr = [];
      for (let n = 0; n < data.length; n++) {
        testArr[n] = data[n];
      }      
      const HelloWorld = require('./build/Release/module.node');
      const result =  HelloWorld.Test(testArr, smin, smax);
    })
    .catch(err => {
      console.log('ERROR during extraction of RED channel. ERR:');
      console.log(err);
    });
  })
  .catch( err => { 
    console.log('ERROR');
    console.log(err);
  });

My problems

  1. Sharp outputs a buffer and not an array but with ArrayBuffer instead of Array I was not able to get working code. Compiling is ok but when I execute it in node I'm getting

Error: Invalid argument at D:\temp\testSCB\index.js:30:34

which is this line of code const result = HelloWorld.Test(testArr, smin, smax);)

  1. If I change redArray[i] = inputArray[i * 3]; to redArray[i] = ~(inputArray[i * 3]); to invert the color I'm getting two errors:

error C2675: unary '~': 'Napi::Value' does not define this operator or a conversion to a type acceptable to the predefined operator

and

error C2088: '~': illegal for class

My Question

What is the correct way to implement my c-Function to work from node.js?

Thanks for any help!

1 Answer 1

3

The node.js team has created Array buffer example by using the node-addon-api (the C++ wrapper to N-API), it can be accessed from the following URL. https://github.com/nodejs/node-addon-examples/tree/master/array_buffer_to_native/node-addon-api

If you are looking for a pure N-API implementation (without using any wrapper) then you may take a look on the following examples, this has been created while I was learning the pure N-API. https://github.com/msatyan/MyNodeC/blob/master/src/mync1/ArrayBuff.cpp.

This example covers the following scenario:

  • Receive an ArrayBuffer from JavaScript
  • Create an ArrayBuffer at native layer and return it to JavaScript
  • Create a TypedArray at native layer and return it to JavaScript
  • Create an ArrayBuffer at native layer with externally allocated memory and return it to JavaScript

Sample JavaScript usage of it is available: https://github.com/msatyan/MyNodeC/blob/master/test/TestArrayBuff.js

If you are starting a new native add-on module, I may encourage to use CMake.js instead of node-gyp (look like node-gyp is ending its support). You can get more information about the modern project structure from a sample project that I have created during my N-API study. https://github.com/msatyan/MyNodeC

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I have used your pure N-API examples which helped me a lot, now I think it should work soon... Also thanks for CMake hint!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.