展示HTML canvas、wasm memory 和 zig 交互的一个小示例。
这个示例来自https://github.com/daneelsan/minimal-zig-wasm-canvas,而这示例本来修改来自https://wasmbyexample.dev/examples/reading-and-writing-graphics/reading-and-writing-graphics.rust.en-us.html。对于当前这个本身,它如大多数 zig 项目一样,zig
命令是你唯一的依赖项。
总结
main.zig
定义了一个全局的 8X8 像素数组: checkerboard_buffer
。并导出三个函数:getCheckerboardBufferPointer()
、getCheckerboardSize()
和 colorCheckerboard(...)
, getCheckerboardBufferPointer()
返回一个指向checkerboard_buffer
开始处的指针,这将在script.js
被使用。getCheckerboardSize()
返回棋盘格子数量。 colorCheckerboard(...)
函数根据传入的颜色参数,来改变棋盘格的颜色。
main.zig
通过build.zig
被编译成 wasm模块 checkerboard.wasm
。
index.html
定义了一个canvas,并指定样式:image-rendering: pixelated; width: 50%
,这是因为main.zig
是定义的一个8x8 象素的棋盘格,所以需要通过 CSS属性image-rendering 来对 canvas 画出的图像进行放大显示,以获得一个清晰的棋盘格来清楚的展示颜色的变化。
script.js
文件创建了一个名为memory
的 WebAssembly.Memory ,它存储的是WebAssembly
实例所访问内存的原始字节码。下一步是使用WebAssembly.instantiateStreaming()
方法编译和示例化获取到的wasm
模块,返回的一个Promise对象,它包含一个instanace
字段(WebAssembly.instanace) , 它保存有从checkerboard.wasm
导出的所有方法。
接下来是:
- 从
WebAssembly.Memory
memory 创建一个Uint8Array
数组:wasmMemoryArray
- 获取到
index.html
中定义的canvascheckerboard
, 并使用getCheckerboardSize()
获取到的棋盘格数来指定canvas 的width
和height
,接着使用canvas的context 创建一个 ImageData 对象:ImageData
在循环中更新棋盘格的颜色:
- 传入RGB颜色参数,调用
colorCheckerboard(...)
,这会修改checkerboard_buffer
中保存的值 checkerboard_buffer
中的内容,是一个段wasmMemoryArray
,可以通过getCheckerboardBufferPointer
获取内存起始地址 和 8 * 8 * 4 字节的偏移长度来获取- 将获取到的内容,放入到
imageData
- 将
imageData
写入到canvas
- 传入RGB颜色参数,调用
构建
build.zig
指定的为一个构建目标是:wasm32-freestanding-musl
用于构建项目的最新zig版本是:
|
|
构建wasm 模块,运行:
|
|
注意: 为了运行将内存导入到 WASM 二进制文件中,构建时需要指定--import-memory
参数
运行
在项目目录上,启动一个服务:
|
|
这时在你的浏览器中浏览:localhost:8000
,就可以看到棋盘格在改变颜色。
资源
- https://github.com/daneelsan/minimal-zig-wasm-canvas
- https://wasmbyexample.dev/examples/reading-and-writing-graphics/reading-and-writing-graphics.rust.en-us.html
- https://radu-matei.com/blog/practical-guide-to-wasm-memory/
- https://developer.mozilla.org/zh-CN/docs/Web/CSS/image-rendering
- https://developer.mozilla.org/zh-CN/docs/Web/API/ImageData
- https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API
- https://developer.mozilla.org/zh-CN/docs/WebAssembly/JavaScript_interface/Memory