使用emscripten如何将C uint8_t数组转换为JS Blob或UInt8Array

在emscripten C中,我有

class MyClass {
public:
   MyClass() {}
   std::shared_ptr<std::vector<uint8_t>> buffer;
   int getPtr() {
      return (int)(buffer->data());
   }
   int getLength() {
      return buffer->size();
   }
};
EMSCRIPTEN_BINDINGS() {
    class_<MyClass>("MyClass").constructor()
      .function("getLength",&MyClass::getLength)
      .function("getPtr",&MyClass::getPtr,
                allow_raw_pointers());
}

我可以从JS调用getLength()和getPtr(),但我不知道如何让JS将它作为​​一个ArrayBuffer来下载为Blob.

如何以一种形式将缓冲区数据导入JS,然后我可以使用类似于https://github.com/kennethjiang/js-file-download/blob/master/file-download.js的代码下载它.

解决方法:

目前,WebAssembly只定义了JS和WASM之间通信的基本数字类型.没有Object类型和Array类型. This is the WebAssembly’s design goal. Emscripten做了一些黑客攻击使C Class< => JS绑定,但它们不是WASM标准.

WebAssembly.Memory()

但有一种方法可以获得阵列.即使没有API,JS也可以直接访问WASM模块的内部存储器. WASM具有线性内存模型,线性内存通过WebAssembly.Memory()接口.WebAssembly.Memory()是单个ArrayBuffer WebAssembly.Memory.buffer,其中WASM模块用作堆内存区域,并且内存分配(例如malloc())发生.

1.以UInt8Array的形式访问它

这是什么意思?这意味着从getPtr()获得的指针(JS方面的整数)实际上是WebAssembly.Memory.buffer的偏移量.

Emscripten自动生成JS(这是从名为preamble.js的模板生成)代码,用于创建WebAssembly.Memory().您可以自己搜索Emscripten生成的代码,并且应该能够找到类似于to this line的行:

Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });

因此,您可以通过Module [‘wasmMemory’]访问WASM模块使用的ArrayBuffer.

let instance = new Module.MyClass();

// ... Do something

let ptr = instance.getPtr();
let size = instance.getLength();
// You can use Module['env']['memory'].buffer instead. They are the same.
let my_uint8_buffer = new Uint8Array(Module['wasmMemory'].buffer, ptr, size);

2. Emscripten HEAPU8

或者,Emscripten提供an official way to access the heap memory region as typed arrays:HEAPU8,HEAPU16,HEAPU32等,如here所定义.所以你可以这样做:

let instance = new Module.MyClass();

// ... Do something

let ptr = instance.getPtr();
let size = instance.getLength();
let my_uint8_buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, size);

使用HEAPU8会更安全,因为HEAPU8已被记录,而Module [‘wasmMemory’]的属性名称有点无证,可能会有所变化;但他们做同样的事情.

3.使用emscripten :: val(仅限C)

Emscripten还为C开发人员提供了一个名为emscripten::val的类,以便在JS和C之间进行交互.为方便起见,这抽象了任何JS / C类型.您可以使用此方法获取阵列.

这是从the documentation和格伦的评论中得到的例子:

#include <emscripten/bind.h>
#include <emscripten/val.h>

emscripten::val getBytes() {
    return emscripten::val(
       emscripten::typed_memory_view(buffer->size(),
                                     buffer->data()));
}

EMSCRIPTEN_BINDINGS() {
    function("getInt8Array", &getInt8Array);
}

然后你可以在JS端调用getInt8Array()来获取类型化的数组.

结论

这里有3个选项可以从WASM获取阵列.无论如何,我认为你应该理解WebAssembly.Memory和选项1背后的东西的概念,因为这是从WASM获取数组的最低级别,最重要的是,这是非托管和不安全的内存访问,因此它很容易在C/C++端释放或修改对象时损坏数据;对于这一具体案例,需要了解低级别影响.

上一篇:java – ArrayBuffer如何在内存中工作?


下一篇:javascript – 如何从ArrayBuffer获取二进制字符串?