Home > Net >  Updating HTML Canvas imagedata using Rust Webassembly
Updating HTML Canvas imagedata using Rust Webassembly

Time:12-12

First post, so forgive me if something is not correct. I am trying to update the image data from a HTML canvas with a PNG file as part of an exercise. The function fetch_url_binary(url: String) returns the pixel information from the PNG.

#[wasm_bindgen] 
pub async fn fetch_url_binary(url: String) -> Result<Uint8Array, JsValue> 
{ 
let window = web_sys::window().unwrap(); // Browser window 
let promise = JsFuture::from(window.fetch_with_str(&url)); // File fetch promise 
let result = promise.await?; // Await fulfillment of fetch 
let response: web_sys::Response = result.dyn_into().unwrap(); // Type casting 
let image_data = JsFuture::from(response.array_buffer()?).await?; // Get text
Ok(Uint8Array::new(&image_data))
}

The function unred(url: String, canvas: String) sets the red channel to zero then updates the canvas with the image.

#[wasm_bindgen] 
pub async fn unred(url: String, canvas: String) -> Result<(), JsValue>
{
    let binary = fetch_url_binary(url).await.unwrap();
    let mut altbuf: Vec<u8> = Vec::new();
    for n in 0..binary.length() {
        if n % 4 == 0 {
            binary.set_index(n,0);
        }
        altbuf.push(binary.get_index(n));
    }
    let window = web_sys::window().unwrap();
    let document = window.document().expect("Could not get document");
    let canvas = document.get_element_by_id(&canvas).unwrap().dyn_into::<web_sys::HtmlCanvasElement>()?;
    let context = canvas.get_context("2d")?.unwrap().dyn_into::<web_sys::CanvasRenderingContext2d>()?;
    let image_data_temp = ImageData::new_with_u8_clamped_array(Clamped(&altbuf), altbuf.len().try_into().unwrap());
    context.put_image_data(&image_data_temp.unwrap(), 0.0, 0.0);
    Ok(()) 
}

The associated HTML code is here:

<!doctype html><html><body> 
  <canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;">
  <script type="module"> 
  import init, {unred, fetch_url_binary} from './pkg/hi_lib.js'; 
  var result;
  async function run() 
  { 
    await init(); // Initialize module 
    unred("myPng.png", "myCanvas");
  } 
  run(); // Execute async wrapper 
</script> 
</body></html>

I then test the code in a python3 http server where I get the following error:

       Uncaught (in promise) hi_lib_bg.wasm:0x5a79  
    RuntimeError: unreachable
    at hi_lib_bg.wasm:0x5a79
    at hi_lib_bg.wasm:0x663a
    at hi_lib_bg.wasm:0x71ba
    at hi_lib_bg.wasm:0x72c9
    at hi_lib_bg.wasm:0x673c
    at hi_lib_bg.wasm:0x20e7
    at hi_lib_bg.wasm:0x3fea
    at hi_lib_bg.wasm:0x7580
    at __wbg_adapter_16 (hi_lib.js:202)
    at real (hi_lib.js:187)
    $func69 @   hi_lib_bg.wasm:0x5a79
$func86 @   hi_lib_bg.wasm:0x663a
$func120    @   hi_lib_bg.wasm:0x71ba
$func126    @   hi_lib_bg.wasm:0x72c9
$func88 @   hi_lib_bg.wasm:0x673c
$func37 @   hi_lib_bg.wasm:0x20e7
$func48 @   hi_lib_bg.wasm:0x3fea
$_dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h51eff7df35816d6c   @   hi_lib_bg.wasm:0x7580
__wbg_adapter_16    @   hi_lib.js:202
real    @   hi_lib.js:187
Promise.then (async)        
imports.wbg.__wbg_then_2fcac196782070cc @   hi_lib.js:440
$func67 @   hi_lib_bg.wasm:0x584d
$func66 @   hi_lib_bg.wasm:0x5709
$func61 @   hi_lib_bg.wasm:0x52af
$func103    @   hi_lib_bg.wasm:0x6cbc
$_dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h51eff7df35816d6c   @   hi_lib_bg.wasm:0x7580
__wbg_adapter_16    @   hi_lib.js:202
real    @   hi_lib.js:187
Promise.then (async)        
imports.wbg.__wbg_then_8c2d62e8ae5978f7 @   hi_lib.js:444
$func44 @   hi_lib_bg.wasm:0x3723
$func45 @   hi_lib_bg.wasm:0x399b
$func37 @   hi_lib_bg.wasm:0x1ad6
$func48 @   hi_lib_bg.wasm:0x3fea
$_dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h51eff7df35816d6c   @   hi_lib_bg.wasm:0x7580
__wbg_adapter_16    @   hi_lib.js:202
real    @   hi_lib.js:187
Promise.then (async)        
imports.wbg.__wbg_then_2fcac196782070cc @   hi_lib.js:440
$func67 @   hi_lib_bg.wasm:0x584d
$func66 @   hi_lib_bg.wasm:0x5709
$func61 @   hi_lib_bg.wasm:0x52af
$func103    @   hi_lib_bg.wasm:0x6cbc
$_dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h51eff7df35816d6c   @   hi_lib_bg.wasm:0x7580
__wbg_adapter_16    @   hi_lib.js:202
real    @   hi_lib.js:187
Promise.then (async)        
imports.wbg.__wbg_then_8c2d62e8ae5978f7 @   hi_lib.js:444
$func44 @   hi_lib_bg.wasm:0x3723
$func45 @   hi_lib_bg.wasm:0x3913
$func37 @   hi_lib_bg.wasm:0x1ad6
$func48 @   hi_lib_bg.wasm:0x3fea
$_dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h51eff7df35816d6c   @   hi_lib_bg.wasm:0x7580
__wbg_adapter_16    @   hi_lib.js:202
real    @   hi_lib.js:187
Promise.then (async)        
imports.wbg.__wbg_then_2fcac196782070cc @   hi_lib.js:440
$func67 @   hi_lib_bg.wasm:0x584d
$func64 @   hi_lib_bg.wasm:0x5503
$func79 @   hi_lib_bg.wasm:0x6202
$wasm_bindgen__convert__closures__invoke2_mut__hc0a39dba83c8fc65    @   hi_lib_bg.wasm:0x7540
__wbg_adapter_55    @   hi_lib.js:296
cb0 @   hi_lib.js:424
imports.wbg.__wbg_new_b1d61b5687f5e73a  @   hi_lib.js:429
$func183    @   hi_lib_bg.wasm:0x77e4
$unred  @   hi_lib_bg.wasm:0x66a2
unred   @   hi_lib.js:226
run @   rust_html.html:16
await in run (async)        
(anonymous) @   rust_html.html:20

I assume it has something to do with the asynchronous code, but I do not have any idea on how to solve it. I am also trying to avoid altering the javascript directly as the exercise should be completable purely in Rust.

EDIT (1) After doing some review, I think the issue is that I convert the Uint8Array into a vector and then Clamp it. It seems like the function expects an clamped array instead.

EDIT (2) I noticed another error, this time with fetch_url_binary(). The Uint8Array does not match the PNG file. There are 44750 with 4 bytes of information (RGBA) associated with each one. The Uint8Array is sized at 6384.

EDIT (3) Request for the Cargo.toml file.

[package]
name = "hi_lib"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2.78" 
wasm-bindgen-futures = "0.4.28" 
image = "0.23.14"

[dependencies.js-sys]
version = "0.3.4"
 
[dependencies.web-sys] 
version = "0.3.55" 
features = ['Response','Window', 'HtmlElement', 'HtmlCanvasElement', 'HtmlImageElement','CanvasRenderingContext2d','Document', 'Element', 'Attr', 'ImageData'] 

I would recommmend going with the Cargo.toml in the answer below. There is definitely a lot of bloat with my version.

CodePudding user response:

Your current code produces an test image

Now when building with wasm-pack build --target web and then serving the crates' root directory with a http server, this is the output: enter image description here

  • Related