我正在尝试使用WebAssembly和Rust创建画布像素数据。作为一个初步的实验,我正在尝试让Rust写入其线性内存,然后我将使用它来创建一个ImageData
对象,以便我可以将其写入画布。
ImageData的基础是一个Uint8Array,其中每个像素由rgba的4个数字组成。我在Rust中使用以下结构表示它:
struct Pixel {
r: u8,
g: u8,
b: u8,
a: u8,
}
我已经将一个函数导出到JavaScript,它将尝试着对500 x 500像素的画布中的全部250,000个像素进行着色:
#[no_mangle]
pub fn color(width: u32, height: u32) {
for i in 0..width * height {
let ptr = (i * 4) as u64 as *mut Pixel;
let mut pixel = unsafe { &mut *ptr };
pixel.r = 10;
pixel.g = 10;
pixel.b = 10;
pixel.a = 255;
}
}
这是前端的相应HTML/JS代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
canvas {
border: 1px solid red;
}
</style>
</head>
<body>
<canvas id="canvas" height="500" width="500"></canvas>
<script>
const WIDTH = 500;
const HEIGHT = 500;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
fetch('/rotate.wasm')
.then((res) => res.arrayBuffer())
.then((ab) => WebAssembly.instantiate(ab))
.then(({ instance }) => {
instance.exports.memory.grow(100); // make memory big enough
instance.exports.color(WIDTH, HEIGHT);
const data = new Uint8ClampedArray(instance.exports.memory.buffer, 0, WIDTH * HEIGHT * 4)
const imageData = new ImageData(data, 500, 500);
ctx.putImageData(imageData, 0, 0);
});
</script>
</body>
</html>
结果是并非所有像素都被着色,只有顶部的一部分:当我检查WebAssembly内存时,我发现它似乎在大约42k像素后停止了着色。