从wasm修改画布

时间:2017-03-15 09:43:50

标签: html5 canvas webassembly

是否可以从Web程序集中有效地修改html5画布?

更新:

var imageData = context.getImageData(x, y, w, h)
var buffer = imageData.data.buffer;  // ArrayBuffer

如果缓冲区可写,可能就是这样。

4 个答案:

答案 0 :(得分:4)

WebAssembly实例通常具有线性内存区域,该区域作为arraybuffer向JavaScript API公开。这可以在JS中分配,并在创建WebAssembly实例时传入,或者WebAssembly实例可以创建它并将其导出到JS代码。无论哪种方式,arraybuffer都可以用来有效地将数据复制到Canvas元素中和从Canvas元素中复制出来(使用createImageData,getImageData和putImageData)。

答案 1 :(得分:4)

不,不是在WebAssembly和web-api开发的这个阶段。 使用context.getImageData,您将获得一个带有新缓冲区的新ImageData对象,该缓冲区必须再次复制到WebAssembly实例的内存缓冲区中。 但是,如果您不需要从画布中读取,只需要编写,则可以在WebAssembly实例的内存中分配ImageData.data。使用ImageData构造函数

imageData = new ImageData(new Uint8ClampedArray(waInstance.export.memory.buffer, byteOffset, width*height*4), width, height)

imageData有一个指向您数据的指针。在每次渲染时,在WebAssembly中完成工作并在imageData中使用相同的context.putImageData(imageData),每个周期只执行一次大数据复制。

答案 2 :(得分:3)

  1. 无论如何,您必须将像素复制到WebAssembly.Memory个实例。然后修改并复制回来。
  2. 我不知道为什么,但Uint8Array.set()在最新的Chrome中并不快。最好将数据重新转换为32位(new Uint32Array(your_uint8array)),然后使用Uint32Array.set()进行复制。
  3. 请注意,canva的.getImageData() / .setImageData()并不快。也许,因为他们做alpha预乘和其他事情。
  4. 总结一下:你的最大速度损失将在.getImageData / .setImageData中,并且无法避免。其他事情有解决方法。

    如果与优化的JS相比,ism会给你10-20%的好处,而不是太多。

答案 3 :(得分:0)

我知道一种解决方案已被接受,但是如果有人落在这里寻找替代方案,我还是会张贴。

我没有积极参与wasm-bindgen防锈工具的开发,但是它目前能够通过网络系统的箱子修改canvas元素。下面显示的代码摘自wasm-bindgen图书页面上的链接。


use std::f64;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

#[wasm_bindgen(start)]
pub fn start() {
    let document = web_sys::window().unwrap().document().unwrap();
    let canvas = document.get_element_by_id("canvas").unwrap();
    let canvas: web_sys::HtmlCanvasElement = canvas
        .dyn_into::<web_sys::HtmlCanvasElement>()
        .map_err(|_| ())
        .unwrap();

    let context = canvas
        .get_context("2d")
        .unwrap()
        .unwrap()
        .dyn_into::<web_sys::CanvasRenderingContext2d>()
        .unwrap();

    context.begin_path();

    // Draw the outer circle.
    context
        .arc(75.0, 75.0, 50.0, 0.0, f64::consts::PI * 2.0)
        .unwrap();

    // Draw the mouth.
    context.move_to(110.0, 75.0);
    context.arc(75.0, 75.0, 35.0, 0.0, f64::consts::PI).unwrap();

    // Draw the left eye.
    context.move_to(65.0, 65.0);
    context
        .arc(60.0, 65.0, 5.0, 0.0, f64::consts::PI * 2.0)
        .unwrap();

    // Draw the right eye.
    context.move_to(95.0, 65.0);
    context
        .arc(90.0, 65.0, 5.0, 0.0, f64::consts::PI * 2.0)
        .unwrap();

    context.stroke();
}

可以从转换为Web程序集的rust代码访问canvas对象。调用Web汇编代码的方式有很多,但是此示例建议的方法是一个包含这些内容的index.js文件,以及一个诸如webpack的捆绑器。

import("path/to/wasm/canvas/code").catch(console.error)

有关此内容的端到端演示,请访问此链接作为参考。

canvas hello world