前端实现简单抠图 vue3+ts
最近有一个简单的想法,拿到图片之后过滤颜色,实现简单的抠图。所以做了一个小demo简单实现了。
技术栈:vue3 + typescript
<template>
<div style="display: flex">
<div class="image-container">
<span class="demonstration">转换前</span>
<img
:src="props._src"
ref="imgRef"
@load="onImageLoad"
@error="onImageError"
crossOrigin="anonymous"
/>
</div>
<div class="image-container">
<span class="demonstration">转化后</span>
<div class="canvas-container texture">
<canvas id="image-canvas" ref="canvasRef"></canvas>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
interface IProp {
_src: string;
scale: number;
}
const props = withDefaults(defineProps<IProp>(), {
_src: () => "",
scale: () => 1, // 设置过滤后的缩放大小
});
const canvasRef = ref<HTMLCanvasElement | null>(null);
const imgRef = ref<HTMLImageElement | null>(null);
function filter(data: Uint8ClampedArray) {
let count = 0; // 记录过滤的像素数量
for (let i = 0; i < data.length; i += 4) {
let r = data[i],
g = data[i + 1],
b = data[i + 2];
// 放宽过滤条件,色值在240-256之间都认为是白色
if ([r, g, b].every((v) => v >= 138)) {
data[i + 3] = 0; // 把白色改成透明的
count++;
}
}
console.log(`Filtered ${count} pixels`);
}
function onImageLoad() {
if (canvasRef.value && imgRef.value) {
const width = imgRef.value.width;
const height = imgRef.value.height;
console.log(width, height);
// 动态设置画布的尺寸
canvasRef.value.width = width;
canvasRef.value.height = height;
const ctx = canvasRef.value.getContext("2d");
if (ctx) {
ctx.scale(props.scale, props.scale); // 缩放画布
ctx.drawImage(imgRef.value, 0, 0);
// 获取画布像素信息
const imageData = ctx.getImageData(0, 0, width, height);
// 一个像素点由RGBA四个值组成,data为[R,G,B,A [,R,G,B,A[...]]]组成的一维数组
// 可以通过修改该数组的数据,达到修改图片内容的目的
const data = imageData.data;
filter(data); // 这里对图像数据进行处理
// 把新的内容画进画布里
ctx.putImageData(imageData, 0, 0);
}
}
}
function onImageError() {
console.error("图片加载失败");
}
</script>
<style scoped lang="less">
.image-container {
box-sizing: border-box;
margin-top: 30px;
margin-right: 30px;
border: 1px solid var(--el-border-color);
border-radius: 10px;
padding: 20px;
}
.demonstration {
text-align: center;
display: block;
color: var(--el-text-color-secondary);
font-size: 14px;
}
.canvas-container {
width: 100%;
}
.texture { /* 设置透明底纹 */
--ccc: #ccc;
---transparent: transparent;
font-size: 0;
background-image: -webkit-gradient(
linear,
0 0,
100% 100%,
color-stop(0.25, var(---transparent)),
color-stop(0.25, transparent),
to(transparent)
),
-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, var(---transparent)), color-stop(0.25, transparent), to(transparent)),
-webkit-gradient(linear, 0 0, 100% 100%, color-stop(0.75, transparent), color-stop(0.75, var(---transparent))),
-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.75, transparent), color-stop(0.75, var(---transparent)));
background-size: 10px 10px;
}
.image-canvas {
scale: 1;
}
</style>