Hi, I'm trying to create an addon which takes raw binary image data as input and then uses various c libraries for image processing. I'm assuming I'll have the image data in Node as a Buffer. I've read through various docs but I'm not sure how to retrieve that information from info into a native c++ object (I guess as a uint8 array or char array?)
Apologies if there's a better place for questions.
Hi @jlipps,
I assume that you are creating a buffer on the JavaScript side and then pass it to C++ side like reported below
const addon = require('your-addon')
// ...
// Creare your buffer
cont buf = Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
// Pass buffer to native function
addon.execute(buf)
On the native side (C++) you can retrieve the buffer object like reported below:
// ...
Napi::Value Exectute(const Napi::CallbackInfo& info) {
// Retrieve the buffer
Napi::Buffer<char> buffer = info[0].As<Napi::Buffer<char>>();
// continue to use the buffer ...
}
// Addon initialization code
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports["execute"] = Napi::Function::New(env, Execute);
return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
I hope that my example could help you. keep me updated about that.
thanks so much @NickNaso I think that's what I was missing. I'll confirm once I've proved it out, but closing for now since it looks like what I need.
Hi again @NickNaso that part worked, now I'm running into trouble getting a napi value from a c-style array, so I can pass it back to node as a Napi::Array. I read the code for the Array class but it didn't seem to have a relevant constructor, or any methods I could use to add elements to it. Is Napi::Array supposed to be read-only?
Hi @jlipps,
at this time you cannot pass the native c-array directly to a contructor of Napi::Array class, instead you need to parse your native array and add every element to Napi::Array object. I report a small piece of code below.
#include <napi.h>
Napi::Value Method(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Array jsNativeArray = Napi::Array::New(env);
for (int i = 0; i < 5; i++) {
jsNativeArray.Set(i, i + 1);
}
return jsNativeArray;
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "getArray"),
Napi::Function::New(env, Method));
return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
Remember that use Napi::Array is not very efficient in terms of performance, so if you want pass back and forth data between JS and C++ use buffer or data view. The simple thing that you need to know is that all JavaScript value are copied when you pass them between C++ and JS and viceversa. I hope that this information help you with your work.
Just wanted to follow up and say that these pointers were what I needed to get going. It's all working now. Thanks again!
I'm glad to hear that it worked for you.
@NickNaso
Is Napi::Buffer<char> buffer = info[0].As<Napi::Buffer<char>>(); making a copy of the original buffer?
Hi @jlipps,
I assume that you are creating a buffer on the JavaScript side and then pass it to C++ side like reported belowconst addon = require('your-addon') // ... // Creare your buffer cont buf = Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ') // Pass buffer to native function addon.execute(buf)On the native side (C++) you can retrieve the buffer object like reported below:
// ... Napi::Value Exectute(const Napi::CallbackInfo& info) { // Retrieve the buffer Napi::Buffer<char> buffer = info[0].As<Napi::Buffer<char>>(); // continue to use the buffer ... } // Addon initialization code Napi::Object Init(Napi::Env env, Napi::Object exports) { exports["execute"] = Napi::Function::New(env, Execute); return exports; } NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)I hope that my example could help you. keep me updated about that.
Hi @ljian3377,
the buffer is not a copy. The underlying data are the same that you passed from JavaScript side. This is the great advantage offered by the buffer api:
Napi::BufferNapi::ArrayBufferNapi::TypedArrayIn general when you pass data from JavaScript side to native side by default the data are copied. This is a very secure way to pass the data, but copying data between JavaScript to C++ and vice versa has a cost that could have an heavy impact on your performance. Use the buffer allow you to avoid the copy because buffer is particular object that is not subjected to the multi-threading rules of V8 (JavaScript engine) and you can interact with it in place from C or C++.
Yeah, you are right. Thanks.
BTW, what do you mean by
buffer is particular object that is not subjected to the multi-threading rules of V8
The only difference I know is that we can access the buffer's underlying data consistently using a pointer, without worrying about it being moved due to the garbage collection process.
IMO the buffer data reference is outside of the scope of the JS runtime, hence it can be accessed by native if run in the same process. This is a great article for exchange of buffers between native and JS but its in napi and not node-addon-api
https://community.risingstack.com/using-buffers-node-js-c-plus-plus/
Most helpful comment
Hi @jlipps,
I assume that you are creating a buffer on the JavaScript side and then pass it to C++ side like reported below
On the native side (C++) you can retrieve the buffer object like reported below:
I hope that my example could help you. keep me updated about that.