简体   繁体   中英

Accessing UInt8ClampedArray in Rust web assembly

I would like to pass an array containing imageData from a Canvas to a Rust function to do some calculation with it. I have set the return type to null the get one way data passing to work:

JS

wasm.initialize({ noExitRuntime: true }).then(module => {
  const printImageData = module.cwrap("print_image_data", null, ["array"]);
  const functions = { add, printImageData };
  main(functions);
});


async function main(wasmFn) {
  const imageData = await getImageData();
  const data = new Uint8Array(imageData.data);
  wasmFn.printImageData(data);
}

Rust

#[no_mangle]
pub fn print_image_data(data: *mut [u8]) -> i32 {
    println!("{:?}", data);
    32
}

When executing this, I get the following error in my browser console:

thread 'main' panicked at 'cannot access stdout during shutdown', /checkout/src/libcore/option.rs:819:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.
uncaught exception: 5261184

How can I access the array from Rust side? How could I then access that data again from JavaScript? I have read that passing back an array is not possible.

EDIT:

at the docs of emscripten I have found the following:

argTypes – An array of the types of arguments for the function (if there are no arguments, this can be omitted). Types are as in returnType, except that array is not supported as there is no way for us to know the length of the array).

Is there another way to do this? Maybe passing a Pointer and accessing the Array somehow? I find it quite hard to find documentation, so any link is appreciated :)

This is one method of accessing a UInt8ClampedArray , based on this code .

JavaScript

fetch('hello_world.gc.wasm')
  .then(r => r.arrayBuffer())
  .then(r => WebAssembly.instantiate(r))
  .then(r => r.instance.exports)
  .then(wasm => {

    const width = 1;
    const height = 1;
    const byteSize = width * height * 4;
    let pointer = wasm.alloc(byteSize);
    let usub = new Uint8ClampedArray(wasm.memory.buffer, pointer, byteSize);
    let img = new ImageData(usub, width, height);
    wasm.abcd(pointer, width, height);

    console.log(`${img.data[0].toString(16)}`);
    console.log(`${img.data[1].toString(16)}`);
    console.log(`${img.data[2].toString(16)}`);
    console.log(`${img.data[3].toString(16)}`);
  });

Rust

use std::mem;
use std::os::raw::c_void;
use std::slice;

// In order to work with the memory we expose (de)allocation methods
#[no_mangle]
pub extern "C" fn alloc(size: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(size);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);
    return ptr as *mut c_void;
}

#[no_mangle]
pub extern "C" fn dealloc(ptr: *mut c_void, cap: usize) {
    unsafe {
        let _buf = Vec::from_raw_parts(ptr, 0, cap);
    }
}

#[no_mangle]
pub extern "C" fn abcd(pointer: *mut u8, width: usize, height: usize) {
    let bytesize: usize = width * height * 4;
    let sl = unsafe { slice::from_raw_parts_mut(pointer, bytesize) };

    // Now you can change your buffer
    sl[0] = 0xaa;
    sl[1] = 0xab;
    sl[2] = 0xac;
    sl[3] = 0xad;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM