原文链接: wasm 前端抠图 性能对比
上一篇: wasm cpp 传值
下一篇: vscode 使用 clang 格式化 c++代码
inline 的对比好像不明显
手动加了inline后, 感觉O3的优化应该是已经做了这些处理了
_________________________________________________________________'';;
目前看来对于计算密集型任务, wasm也就那样了, 相比与开发难度(c++/c) 以及移动端的支持来讲, 不是很推荐使用....尤其是需要兼容什么安卓4, ios9之类的, 想都不想js一把梭
如果是纯桌面端, 且能够把控设备和浏览器的话, 还是可以试试的
大概也能提高30%左右.............
不过目前打包后的js文件, 如果使用webpack的import语法引入, 会报fs找不到的问题, 需要使用script标签引入
后面有时间看看怎么能用import 引入
几次试下来基本上数据波动不大
index.vue
<template>
<div class="wrap">
<img
@click="clickInput"
class="box"
ref="inputRef"
:src="imageUrl"
alt=""
/>
<canvas :style="canvasStyleRef" ref="canvasRef" class="box"></canvas>
<img :style="canvasStyleRef" ref="outputRef" class="box" src="" alt="" />
</div>
</template>
<script>
import { ref, onMounted } from "vue";
import { delColor } from "./util";
export default {
props:['imageUrl'],
setup(props) {
console.log("props", props);
const imageUrl = ref(props.imageUrl);
const canvasRef = ref(null);
const outputRef = ref(null);
const inputRef = ref(null);
const canvasStyleRef = ref("");
// 将图片绘制到canvas中
const input = () => {
if (!inputRef.value || !canvasRef.value) return;
console.log("input");
canvasRef.value
.getContext("2d")
.drawImage(
inputRef.value,
0,
0,
inputRef.value.width,
inputRef.value.height
);
};
// 将canvas中的内容画到图片中
const output = () => {
if (!outputRef.value || !canvasRef.value) return;
console.log("output");
const url = canvasRef.value.toDataURL("image/png", 1);
outputRef.value.src = url;
};
onMounted(() => {
inputRef.value.onload = () => {
// const { width, height } = inputRef.value.getBoundingClientRect();
canvasRef.value.width = inputRef.value.width;
canvasRef.value.height = inputRef.value.height;
// canvasRef.value.height = width;
// canvasRef.value.height = height;
input();
output();
console.log(inputRef.value.width);
canvasStyleRef.value = `width:${canvasRef.width}px;height:${canvasRef.height}px`;
};
});
const clickInput = (e) => {
console.log(e);
const x = e.offsetX;
const y = e.offsetY;
const color = canvasRef.value.getContext("2d").getImageData(x, y, 1, 1)
.data;
delColor(canvasRef.value, x, y, color);
output();
};
return {
clickInput,
canvasRef,
canvasStyleRef,
inputRef,
outputRef,
imageUrl,
};
},
};
</script>
<style lang="less">
.wrap {
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
height: 100%;
.box {
// width: 100%;
// width: 25%;
// height: auto;
}
}
</style>
uitl.js
function fillWasm(data, x, y, w, h) {
const size = data.length;
const ccall = Module.ccall;
const numBytes = size * Uint8Array.BYTES_PER_ELEMENT;
const ptr = Module._malloc(numBytes);
const heapBytes = new Uint8Array(Module.HEAP8.buffer, ptr, numBytes);
const imageDataBuffer = Uint8Array.from(data);
heapBytes.set(new Uint8Array(imageDataBuffer));
const st = +new Date();
ccall(
"fillWasm",
"null",
["Uint8Array", "number", "number", "number", "number"],
[heapBytes.byteOffset, x, y, w, h]
);
console.log("time wasm:", +new Date() - st);
const resultArray = new Uint8Array(Module.HEAP8.buffer, ptr, size);
const result = new Uint8ClampedArray(resultArray);
return result
}
// console.log(wasmModule)
export const delColor = (canvas, x, y) => {
const w = canvas.width;
const h = canvas.height;
const ctx = canvas.getContext("2d");
const { data, width, height } = ctx.getImageData(0, 0, w, h);
const newData = fillWasm(data, x, y, width, height);
const b2 = new ImageData(newData, width, height);
ctx.putImageData(b2, 0, 0);
};
fillWasm.cpp
#include <stdlib.h>
#include <emscripten.h>
#include <iostream>
#include <stack>
#include <map>
using namespace std;
void setColor(uint8_t *data, int x, int y, int w, uint8_t *c)
{
for (int i = 0; i < 4; i++)
{
data[(y * w + x) * 4 + i] = c[i];
}
}
uint8_t *getColor(uint8_t *data, int x, int y, int w)
{
return data + (y * w + x) * 4;
}
bool compare(uint8_t *c1, uint8_t *c2)
{
int d = abs(c1[0] - c2[0]) + abs(c1[1] - c2[1]) + abs(c1[2] - c2[2]);
return d < 100;
}
extern "C"
{
void fillWasm(uint8_t *data, int x, int y, int w, int h);
}
bool canVisit(map<int, bool> &v, int x, int y, int w, int h)
{
if (x < 0 || y < 0 || x >= w || y >= h)
return 0;
return !v[(x << 16) + y];
}
void setVisit(map<int, bool> &v, int x, int y, bool value)
{
v[(x << 16) + y] = value;
}
void fillWasm(uint8_t *data, int x, int y, int w, int h)
{
int byteSize = w * h * 4;
uint8_t *dataMock = new uint8_t[byteSize];
memcpy(dataMock, data, byteSize);
uint8_t *sourceColor = getColor(dataMock, x, y, w);
uint8_t fillColor[] = {98, 237, 240, 255};
uint8_t redColor[] = {255, 0, 0, 255};
map<int, bool> v;
int directionSize = 4;
int direction[4][2] = {
{0, 1},
{0, -1},
{1, 0},
{-1, 0},
};
stack<int *> st;
int init[3] = {x, y, 0};
st.push(init);
int count = 0;
while (st.size())
{
count++;
int *top = st.top();
int tx = top[0];
int ty = top[1];
int td = top[2];
setColor(data, tx, ty, w, fillColor);
setVisit(v, tx, ty, 1);
if (td == directionSize)
{
st.pop();
continue;
}
int dx = direction[td][0];
int dy = direction[td][1];
int nx = tx + dx;
int ny = ty + dy;
top[2]++;
if (
canVisit(v, nx, ny, w, h) &&
compare(sourceColor, getColor(dataMock, nx, ny, w)))
{
int *ptr = new int[3];
ptr[0] = nx;
ptr[1] = ny;
ptr[2] = 0;
st.push(ptr);
setVisit(v, tx, ty, 1);
}
else if (
nx >= 0 &&
ny >= 0 &&
nx < w &&
ny < h &&
!compare(sourceColor, getColor(dataMock, nx, ny, w)))
{
setColor(dataMock, nx, ny, w, redColor);
}
}
cout << "count:" << count << endl;
}
int main(int argc, char **argv)
{
return 0;
}
/*
emcc -O3 -s \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","ccall"]' \
-s EXPORTED_FUNCTIONS='["_main","_fillWasm"]' \
-s ALLOW_MEMORY_GROWTH \
fillWasm.cpp
*/