4

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 :)

5
  • Why do you think you aren't accessing the array? Why do you need to pass "back" the array if you've only transferred a pointer to the array? Are you sure that stdout is even properly configured? The error message seems to indicate otherwise; try just setting a value in the array and using console.log on the calling side. Commented Oct 23, 2017 at 17:18
  • I presume you'd use the same solution that people use for C / C++ - i.e. communicate a memory address which is the start of the array stackoverflow.com/questions/46748572/… Commented Oct 23, 2017 at 21:21
  • @ColinE that would be literally what the current code does (data: *mut [u8]) thus why I asked such in my previous comment. Commented Oct 23, 2017 at 22:20
  • I tried it out with an add function. Adding two numbers in rust and then printing the result on the calling side. I also printed 'Hello world!' from the Rust side. All working fine. Also the array contains data of an Image. Printing it works from JS. Commented Oct 24, 2017 at 11:56
  • You may have missed out the extern on pub fn print_image_data(...). But see my complete answer that works for me below. Commented Jun 14, 2018 at 3:37

1 Answer 1

2

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;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.