简单的循环操作, 原生js的速度也很快, 对于需要进行io的wasm来说, 性能反而会稍微慢一点
原地操作数组, 会有一些提升的空间
js版本
Title
const grayJs = (data, w, h) => {
const size = w * h;
for (let i = 0; i < size; i++) {
const j = i * 4;
const g = ((data[j] + data[j + 1] + data[j + 2]) / 3) | 0;
// const g = Number((data[j] + data[j + 1] + data[j + 2]) / 3)
data[j] = data[j + 1] = data[j + 2] = g;
}
};
const input = document.getElementById("input");
const canvas = document.createElement("canvas");
const output = document.createElement("canvas");
const test = () => {
const w = input.width;
const h = input.height;
canvas.width = output.width = w;
canvas.height = output.height = h;
const ctx = canvas.getContext("2d");
ctx.drawImage(input, 0, 0);
document.body.append(canvas);
const imageData = ctx.getImageData(0, 0, w, h);
const i = new Uint8ClampedArray();
console.log(imageData);
imageData.data[0] = 0;
const st = +new Date();
grayJs(imageData.data, w, h);
console.log("time:", +new Date() - st, imageData.data.length);
console.log(imageData);
output.getContext("2d").putImageData(imageData, 0, 0);
document.body.append(output);
};
document.addEventListener("click", test);
wasm版本
Document
let imageData;
let w;
let h;
const input = document.getElementById("input");
const canvas = document.createElement("canvas");
const output = document.createElement("canvas");
input.onload = () => {
w = input.width;
h = input.height;
canvas.width = output.width = w;
canvas.height = output.height = h;
const ctx = canvas.getContext("2d");
ctx.drawImage(input, 0, 0);
document.body.append(canvas);
imageData = ctx.getImageData(0, 0, w, h);
// console.log("imageData", imageData.data.length);
};
Module.onRuntimeInitialized = () => {
console.log("===", imageData, w, h);
console.log("wasm", Module);
};
function test() {
const size = imageData.data.length;
const ccall = Module.ccall;
const numBytes = size * Uint8Array.BYTES_PER_ELEMENT;
// console.log("size", { size, numBytes, w, h });
const ptr = Module._malloc(numBytes);
const heapBytes = new Uint8Array(Module.HEAP8.buffer, ptr, numBytes);
const imageDataBuffer = Uint8Array.from(imageData.data);
// console.log("imageDataBuffer", imageDataBuffer);
heapBytes.set(new Uint8Array(imageDataBuffer));
const st = +new Date();
const resultPtr = ccall(
"grayCpp",
"Uint8Array",
["Uint8Array", "number", "number"],
[heapBytes.byteOffset, w, h]
);
console.log("time:", +new Date() - st);
// console.log("resultPtr", resultPtr);
const resultArray = new Uint8Array(
Module.HEAP8.buffer,
resultPtr,
size
);
// console.log("resultArray", resultArray);
const result = new Uint8ClampedArray(resultArray);
// console.log("result", result.length);
const outputData = new ImageData(result, w, h);
output.getContext("2d").putImageData(outputData, 0, 0);
document.body.append(output);
}
document.addEventListener("click", test);
grayCpp.cpp
#include
#include
#include
#include
using namespace std;
extern "C"
{
uint8_t *grayCpp(uint8_t *data, int w, int h);
}
uint8_t *grayCpp(uint8_t *data, int w, int h)
{
int byteSize = sizeof(uint8_t) * w * h * 4;
cout << "byteSize:" << byteSize << endl;
uint8_t *ptr = (uint8_t *)malloc(byteSize);
memcpy(ptr, data, byteSize);
uint8_t g;
int size = w * h;
int j = 0;
for (int i = 0; i < size; i++)
{
j = i * 4;
g = (data[j] + data[j + 1] + data[j + 2]) / 3;
ptr[j] = ptr[j + 1] = ptr[j + 2] = g;
}
return ptr;
}
int main(int argc, char **argv)
{
return 0;
}
/*
emcc -O3 -s \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","ccall"]' \
-s EXPORTED_FUNCTIONS='["_main","_grayCpp"]' \
-s ALLOW_MEMORY_GROWTH \
grayCpp.cpp
*/
grayC.c
#include
#include
#include
EMSCRIPTEN_KEEPALIVE
void grayCpp(uint8_t *data, int w, int h)
{
int i,j;
uint8_t g;
int size = w * h;
for ( i = 0; i < size; i++) {
j = i * 4;
g = ((data[j] + data[j + 1] + data[j + 2]) / 3);
// const g = Number((data[j] + data[j + 1] + data[j + 2]) / 3)
data[j] = data[j + 1] = data[j + 2] = g;
}
}
EMSCRIPTEN_KEEPALIVE
uint8_t* create_buffer(int width, int height)
{
return (uint8_t *)malloc(width * height * 4 * sizeof(uint8_t));
}
int main(int argc, char **argv)
{
// int i;
// for (i = 0; i < 10; i++)
// printf("hello %d %d \n", i, fib(1));
create_buffer(1,1);
return 0;
}
// emcc fib.c -s WASM=1 -s -o fib.html
// emcc fib.cpp -s WASM=1 -s -o fib.html
// emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","fib"]' fib.cpp
// emcc -O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","create_buffer","grayCpp"]' grayCpp.cpp
// emcc -O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","create_buffer","grayCpp"]' grayCpp.c
/*
emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-I libwebp \
grayCpp.cpp \
-s ALLOW_MEMORY_GROWTH \
emcc -O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","fib"]' grayCpp.cpp
emcc -O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","ccall","create_buffer","grayCpp"]' grayCpp.cpp
*/