Используя 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());
}

Я могу вызвать getLength () и getPtr () из JS, но я не знаю, как заставить JS рассматривать его как ArrayBuffer для загрузки как BLOB-объекта.

Как я могу получить данные буфера в JS в форме, где я могу затем загрузить их, используя код, подобный https://github.com/kennethjiang/js-file-download/blob/master/file-download.js.

1

Решение

В настоящее время WebAssembly определяет только основные типы номеров для связи между JS и WASM. Здесь нет ни типов объектов, ни типов массивов. Это цель дизайна WebAssembly. Emscripten сделал несколько хаков, чтобы сделать C ++ Class <=> JS привязки, но они не являются стандартом WASM.

WebAssembly.Memory ()

НО есть способ получить массив. JS имеет прямой доступ к внутренней памяти модуля WASM, даже без API. WASM имеет линейную модель памяти, а линейная память соединена через WebAssembly.Memory(). WebAssembly.Memory() это один ArrayBuffer WebAssembly.Memory.buffer где ваш модуль WASM использует в качестве области динамической памяти и где выделяется память (например, malloc()) бывает.

1. Доступ к нему как к UInt8Array

Что это значит? Это означает, что указатель (целое число на стороне JS), который вы получаете от getPtr() на самом деле смещение WebAssembly.Memory.buffer,

Emscripten автоматически генерирует JS (это генерируется из шаблона под названием preamble.js) код, который создает WebAssembly.Memory(), Вы можете искать код, сгенерированный Emscripten, самостоятельно и сможете найти строку, аналогичную к этой линии:

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

Таким образом, вы можете получить доступ к ArrayBuffer, используемому вашим модулем WASM, через Module['wasmMemory'].buffer:

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 предлагает официальный способ доступа к области памяти кучи в виде типизированных массивов: HEAPU8,HEAPU16, HEAPU32и т. д., как определено Вот. Так что вы можете сделать так:

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 также предоставляет класс под названием emscripten::val для разработчиков C ++ взаимодействовать между JS и C ++. Это абстрагирует любые типы JS / C ++ для удобства. Вы можете получить массив, используя это.

Это пример, взятый из документация и комментарий Гленна:

#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);
}

Тогда вы можете позвонить getInt8Array() в сторону JS, чтобы получить типизированный массив.

Заключение

Для получения массива из WASM предлагается 3 варианта. В любом случае, я думаю, что вы должны понимать понятия WebAssembly.Memory и что стоит за вариантом 1, потому что это самый низкий уровень для получения массива из WASM, и, самое главное, это неуправляемый и небезопасный доступ к памяти, поэтому легко испортить данные когда объект освобождается или модифицируется на стороне C / C ++; Знание последствий низкого уровня требуется для этого конкретного случая.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]