解説
「Wasm」は「WebAssembly」の略です。Wasmは、架空のプロセッサに対する命令セットで、Webブラウザー上で高速に処理をおこなうために作られました。もともと、Mozilla Foundationの技術者たちが主導で開発が始まり、その後各ブラウザーに広がりました。
Wasmを作る際は、コンパイラを利用して、CやC++、Rust、Goなどから変換します。Webページでは、コンパイラが作った.wasmファイルを読み込んで、Wasmとして実行します。
Wasmは高速なだけでなく、WebブラウザーさえあればOSなどの実行環境を問わないために、多くの環境で利用できる利点があります。
サンプル
「Wasm」のサンプルです。※ サーバー上で実行する必要があります。
#include <cstdint>
extern "C" {
void to_gbr(uint8_t* src, int len, int w, int h, uint8_t* dst) {
int pixel_size = w * h;
for (int i = 0; i < pixel_size; i ++) {
int base = i * 4;
if (base + 3 > len) break;
int r = src[base + 0];
int g = src[base + 1];
int b = src[base + 2];
int a = src[base + 3];
dst[base + 0] = g;
dst[base + 1] = b;
dst[base + 2] = r;
dst[base + 3] = a;
}
}
}
emcc "src/img_filter.cpp" -O3 ^
-s EXPORTED_FUNCTIONS="['_to_gbr','_malloc','_free']" ^
-o "dst/img_filter.js"
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>「Wasm」のサンプル</title>
<style> img { max-width: 100%; } </style>
<script src="./img_filter.js"></script>
</head>
<body>
<script>
window.addEventListener('DOMContentLoaded', e => {
Module.onRuntimeInitialized = async () => {
// 画像を読み込んでページに表示
const {img, w, h, data} = await getImgData('./img.png');
document.body.appendChild(img);
// Wasmの利用
// malloc / コピー / 実行 / 取得 / free
const len = data.length;
const srcPtr = Module._malloc(len);
const dstPtr = Module._malloc(len);
HEAPU8.set(data, srcPtr);
Module._to_gbr(srcPtr, len, w, h, dstPtr);
const res = new Uint8Array(HEAPU8.subarray(dstPtr, dstPtr + len));
Module._free(srcPtr);
Module._free(dstPtr);
// Canvas→PNGを生成して、ページに表示
const imgElement = uint8ArrToImgElement(res, w, h);
document.body.appendChild(imgElement);
};
});
// 画像データの読み込み
// 横幅、高さ、Pixelデータを取り出し
async function getImgData(src) {
const imgData = await new Promise(resolve => {
const img = new Image();
img.src = src;
img.onload = () => {
const res = {};
const w = img.naturalWidth;
const h = img.naturalHeight;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
resolve({img, w, h, data});
};
});
return imgData;
}
// Uint8Arrayの画像からImageElementを得る
function uint8ArrToImgElement(arr, w, h) {
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
const clamped = new Uint8ClampedArray(arr);
const newImageData = new ImageData(clamped, w, h);
ctx.putImageData(newImageData, 0, 0);
const png = canvas.toDataURL('image/png');
const imgElement = document.createElement('img');
imgElement.src = png;
return imgElement;
}
</script>
</body>
</html>
上が元画像。下がWasmで処理した画像。
フィードバックお待ちしております!
ご感想、解説してほしい用語、解説内容のアドバイスなどございましたら、FacebookやX(旧Twitter)などでお気軽に編集部までお寄せください。よろしくお願いいたします。
