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!

groboter
  • 81
  • 2
  • 6

1 Answers1

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

Satyan
  • 1,346
  • 8
  • 15
  • 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! – groboter Jan 19 '20 at 14:43