起初在boss上看到一个面试官发题,利用canvas实现图片裁切,在学习过程中实现三个小功能,并在此基础上深入学习明白相关工具和能力。 这篇博客主要实现三个功能:刮刮卡、在线签名、图片涂抹裁切具体实现效果下图:
一、基础知识
在实现下面功能首先的先明白canvas是做什么的?能解决什么问题?
Canvas是一个HTML元素,可用于在网页上绘制图形、动画和其他可视化效果。它通过JavaScript编程接口来实现。
Canvas可以用于各种任务,包括绘制图表、创建游戏、制作交互式的用户界面等。它可以处理大量的图形和动画,并且具有良好的性能和响应速度。
Canvas的优势包括:
- 强大的绘图功能:Canvas提供了丰富的API,可以实现复杂的绘图操作。
- 高性能:由于直接操作像素,Canvas通常比其他方法(如SVG)更高效。
- 跨浏览器支持:Canvas是HTML5标准的一部分,得到了广泛的支持。
Canvas的一些劣势:
- 缺乏内置的事件处理:相比其他更高级的技术(如React或Angular),Canvas需要手动处理用户交互和事件。
- 不支持文本选择和复制:由于Canvas是基于像素的,无法直接选中或复制其中的文本。
- 难以维护和重构:由于Canvas是基于绘图指令的,代码可能会变得冗长和难以理解,尤其是对于复杂的图形和动画效果。
Canvas可以实现功能,例如:
- 绘制动态图表和数据可视化:Canvas可以根据数据的变化实时更新图表,让用户能够更好地理解数据。
- 创建基于Web的游戏:Canvas提供了一个绘制图形和动画的环境,使开发者能够创建复杂的游戏效果。
- 实现自定义用户界面(banner广告):Canvas可以用于绘制自定义的用户界面元素,使应用程序有更多的创意和自由度。
二 canvas使用
1 创建画布和画笔
提供一个<canvas>
标签(html)、有一个canvas对象(js-画布)、有一个context对象(js-画笔)、CanvasRenderingContex t2D
。有两种声明方式: 一种直接定义canvas标签、另一种通过js创建canvas并通过dom元素添加到页面。
第一种
html
<canvas id="c1"></canvas>
<script>
const convas1 = document.querySelector('#c1');
const context1 = canvas1.getContext('2d');
</script>
第二种
js
var canvas = document.createElement("canvas");
const context = canvas.getContext('2d');
document.body.appendChild(canvas);
注:实际操作使用第二种更加友好,因为通过第二种的添加方式,可以在调用canvasAPI时候有代码提示。
一般设置画布和画笔都会做前置条件,例如:设置画布大小,画笔的粗细颜色等信息,例如:
js
var canvas = document.createElement("canvas");
canvas.classList.add("scratcanvas");
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
2 画笔
画笔有两种3D和2D两种,演示功能主要使用2d画笔,所以接下来围绕2d画笔说。
2D画笔具有以下功能:
- 绘制形状:可以使用画笔绘制直线、曲线、多边形、矩形、圆和椭圆等基本形状。
- 填充和描边:可以为绘制的形状设置填充色和描边色,以实现不同的样式效果。
- 文字绘制:可以使用画笔在画布上绘制文本,包括设置字体、大小、对齐方式等。
- 图像绘制:可以将图像绘制到画布上,用于显示图片或者创建动画效果。
- 渐变和模式:可以创建线性渐变、径向渐变和图案等特殊效果,以增加绘制的视觉吸引力。
- 变换操作:可以对绘制的形状进行平移、旋转、缩放等变换操作,以实现更复杂的绘图效果。
- 合成和透明度:可以设置不同的合成操作和透明度,从而实现图像的混合和透明效果。
- 图形裁剪:可以通过路径裁剪,只显示路径内的内容,实现自定义的图形遮罩效果。
具体各种用法可以看官方文档Canvas - Web API 接口参考,这里用划线举个例子: 绘制直线&折线 两天之间的连线:直线;多个直线连接 : 折线。使用ctx.moveTo(x,y) 将画笔放置到指定的坐标位置 (起始点)。使用ctx.lineTo(x,y) 从上一个点绘制直线路径到指定的点。
- 上一个点可以是moveTo指定的点。
- 上一个点也可以是上一次lineTo指定的点。也就是可以多个lineTo连续使用,形成折线。
3 beginPath
使用context.beginPath()
方法,为不同部分的途径设置开关(设置分组)。只对紧邻这组路径进行绘制。通过这种方式,表示绘图上下文以下绘画的路径方式将不会影响之前绘画内容。
js
ctx.beginPath();
ctx.moveTo(50,50);//开始绘画点
ctx.lineTo(250,50);//经过点
ctx.stroke();//结束直线绘制
举个例子
js
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 开始创建新的路径
ctx.beginPath();
// 定义路径
ctx.moveTo(50, 50);
ctx.lineTo(100, 50);
ctx.lineTo(100, 100);
// 设置路径样式
ctx.lineWidth = 2;
ctx.strokeStyle = 'red';
// 绘制路径
ctx.stroke();
// 开始创建另一个新的路径
ctx.beginPath();
// 定义另一个路径
ctx.arc(150, 75, 50, 0, Math.PI * 2);
// 设置路径样式
ctx.fillStyle = 'blue';
// 填充路径
ctx.fill();
在上述示例中,首先调用了beginPath()来开始创建第一个路径,然后绘制了一条由两个线段组成的路径,最后调用stroke()方法将路径描边。 接着,又调用了beginPath()来开始创建第二个路径,然后使用arc()方法定义了一个圆形路径,并使用fill()方法填充路径。 通过使用beginPath()方法将不同的路径分隔开来,可以确保不同路径的样式和绘制操作互不影响。 ## 4 清除画布 当画笔在画布很多内容,想清空可以调`clearRect`方法,通过调用clearRect()方法并传入相应的参数,可以在Canvas上清除特定区域的绘制内容。
clearRect()方法接受四个参数,分别是:
- x:矩形左上角的 x 坐标。
- y:矩形左上角的 y 坐标。
- width:矩形的宽度。
- height:矩形的高度。
js
context4.closePath()
context4.clearRect(0,0,width,height);
5 引入图像
在画布上引入图像的方式需要通过
- Image对象 对应img标签。
- 可以是图片的路径
- 图片的base64表示
通过drawImage将image塞入到canvas组件中,绘制图像参数:
- image:要绘制的图像。
- x:目标图像左上角的 x 坐标。
- y:目标图像左上角的 y 坐标。
- width:目标图像的宽度。
- height:目标图像的高度。
js
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let preimg = new Image();
preimg.src = "./sub.png";
preimg.onload = function(){
ctx.drawImage(preimg,0,0,width,height);
}
6 图像合成
图像合成是指在Canvas中将多个图像或者样式叠加在一起,从而创建出复杂的绘图效果。这个就是canvas能够实现很多复杂多变效果的方式,目前还没有研究透彻。 主要是利用是globalCompositeOperation
属性。该属性用于设置绘制操作时的合成模式,决定了新的绘制内容如何与已有的内容进行合成。 列举一些 globalCompositeOperation属性可以设置为不同的值来实现不同的合成效果。以下是常见的一些值:
- source-over(默认):新的绘制内容会覆盖在已有内容上方。
- source-in:新的绘制内容只会覆盖与已有内容重叠的部分,并保留其他部分的透明度。
- source-out:新的绘制内容只会覆盖与已有内容不重叠的部分,并保留其他部分的透明度。
- source-atop:新的绘制内容会覆盖与已有内容重叠的部分,并保留其他部分的透明度。
- destination-over:新的绘制内容会在已有内容下方进行绘制。
- destination-in:新的绘制内容只会在与已有内容重叠的部分显示,并保留其他部分的透明度。
- destination-out:新的绘制内容只会在与已有内容不重叠的部分显示,并保留其他部分的透明度。
- destination-atop:新的绘制内容会在与已有内容重叠的部分显示,并保留其他部分的透明度。
- lighter:新的绘制内容与已有内容进行颜色相加,产生更亮的效果。
- xor:新的绘制内容与已有内容进行异或运算。 合成效果如下图: 可以详细的使用可以看这篇帖子Canvas学习:globalCompositeOperation详解 - 方帅 - 博客园 (cnblogs.com)
二、刮刮乐效果
实现刮刮乐效果是通过两张图层进行重叠实现,一张是img或div作为结果放在底部,在上面覆盖一层canvas灰色的画布进行遮盖,当鼠标在canvas上移动则消除灰色区域从而实现刮刮卡效果
1 初始化
在页面上写一个div
html
<div id="card">
</div>
接下来在card的div中绘制开奖结果div
js
//统一宽高
const width = 400;
const height = 300;
//创建一个开奖结果
//创建画布,用户刮开则显示开奖结果
let div = document.createElement("div");
div.innerText = "一等奖"
div.className = "scrat"
document.getElementById("card").appendChild(div);
2 创建canvas
使用canvas创建绘制刮刮乐蒙版
js
//创建一个canvas
var canvas = document.createElement("canvas");
canvas.classList.add("scratcanvas");
//设置宽高
canvas.width = width;
canvas.height = height;
//设置画笔
const context = canvas.getContext('2d');
通过画笔中的fillstyle实现将某个区域填充灰色。
js
//画一个灰色画布遮住界面
context.fillStyle = "#EFEFEF";
context.fillRect(0,0,width,height);
再通过画笔绘制线条,之后通过线条和页面中重叠的地方进行消除,即可实现刮刮卡效果,将canvas添加到class叫scrat的div中。
js
//画一个圆
//画笔分割
context.beginPath();
//设置画笔的粗细
context.lineWidth=20;
//转角和端点设置为圆弧
context.lineCap ="round"
context.lineJoin = "round"
document.getElementsByClassName("scrat")[0].appendChild(canvas);
3 添加鼠标事件
添加点击移动事件,主要是监听用户鼠标三个事件,1、按下鼠标左键;2、移动鼠标;3、抬起鼠标左键。具体实现通过document.addEventListener
来监听mousedown
、mousemove
、mouseup
三种情况,修改鼠标状态isMouseDown
的true和false来实现。
新旧图层重叠部分透明是通过## 6 图像合成的方法globalCompositeOperation
的参数destination-out
实现新图层和旧图层重叠,则展示旧图层未被重叠的区域。
js
//鼠标是否按下状态
var isMouseDown = false;
//鼠标按下,划线
document.addEventListener('mousedown', function(event) {
isMouseDown = true;
//新旧图层重叠部分透明
context.globalCompositeOperation = 'destination-out';
//封装函数,通过getCanvasPosition传入鼠标位置,获取在canvas中对应的位置
var {x,y} = getCanvasPosition(event);
//开始画线
context.moveTo(x,y);
});
// 在这里可以对鼠标位置进行处理
document.addEventListener('mousemove', function(event) {
if(!isMouseDown) return;
var {x,y} = getCanvasPosition(event);
context.lineTo(x,y);
context.stroke();
});
document.addEventListener('mouseup', function(event) {
isMouseDown = false;
});
//封装函数。计算canvas位置
function getCanvasPosition(event) {
//获取鼠标当前位置
var x = event.clientX;
var y = event.clientY;
//减去div的位置
x -= div.offsetLeft;
y -= div.offsetTop;
//减去canvas的位置
x -= canvas.offsetLeft;
y -= canvas.offsetTop;
return {x,y};
}
最后再调整下页面的样式,通过子绝父相
的css来实现重叠。
css
.scrat {
width: 400px;
height: 300px;
text-align: center;
line-height: 300px;
font-size: 64px;
position: relative;
border: 1px solid #000;
}
.scratcanvas{
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
}
4 最终效果
三、电子签字组件
当会了刮刮卡效果后可以在此基础上实现电子签名的功能,同样是使用画笔的功能,同样可以先创建一个div,并添加三个按钮
html
<div>
<div class="sign">
<div>
<button id="save">开始</button>
<button id="anew">重签</button>
<button id="eraser">橡皮擦</button>
</div>
</div>
</div>
1 初始化
在初始化设置canvas的基本属性,例如:宽度、高度、笔触转角和端点,并设置基础参数是否开启签名状态、是否开启橡皮擦、笔粗细、笔颜色等。
js
/**
* 签名组件
*/
const width = 400;
const height = 300;
var isSign = false;//是否开启签名状态
var isEraser = false;//是否开启橡皮擦
var brushSize = 10;//笔粗细
var brushColor = "#000";//笔颜色
//签名组件
const draw = document.createElement("canvas");
draw.classList.add("draw");
draw.width = width;
draw.height = height-30;
draw.style.border = "1px solid #ccc";//设置边框
var temp = document.getElementsByClassName("sign")[0];
temp.appendChild(draw);
//2d画笔
var context2 = draw.getContext('2d');
context2.lineCap = "round";
context2.lineJoin = "round";
context2.lineWidth = brushSize;
2 鼠标事件
封装一个画笔事件drawEvent()
,之前通过document.addEventListener
来监听mousedown
、mousemove
、mouseup
三种,其实也可以通过组件的onmousedown
、onmousemove
、onmouseup
实现:1、按下鼠标左键;2、移动鼠标;3、抬起鼠标左键的事件监听,原理像常用的onclick
一样。
由于是签字所以会涉及两个状态,isSign
(是否开启签名状态)、isEraser
(是否开启橡皮擦)通过这两个状态来控制是否清除画布。
最后鼠标抬起,则清空鼠标移动和抬起事件,当用户再次按下鼠标则再次循环执行该事件,具体实现可以看下列详细代码。
js
//调用画笔事件方法
drawEvent() ;
//封装画笔事件
function drawEvent() {
draw.onmousedown = function(event) {
//判断是否开启签字
if (!isSign) return;
// 判断是签字还是橡皮擦
if (isEraser) {
// 如果橡皮擦则调用destination-out进行覆盖清除画布
context2.globalCompositeOperation = 'destination-out';
}else{
//如果是签字则让签字的内容进行重叠显示
context2.globalCompositeOperation = 'source-over';
}
context2.beginPath();
//开始绘画
context2.moveTo(event.offsetX,event.offsetY);
设置点击事件
draw.onmousemove = function(event) {
//判断是否用橡皮擦
if (isEraser) {
// 设置橡皮擦粗细
context2.lineWidth = brushSize;
}else{
//设置签字颜色
context2.strokeStyle = brushColor;
}
//绘画路径坐标
context2.lineTo(event.offsetX,event.offsetY);
//结束绘画
context2.stroke();
}
//当鼠标左键抬起,则将移动事件和抬起事件设置为空
draw.onmouseup = function(event) {
draw.onmousemove = null;
draw.onmouseup = null;
}
}
}
3 开启or保存下载
由于上面封装画笔事件所以可以改变画笔状态调用drawEvent()
方法即可,给开启签字添加相关事件
js
//开启签字,或关闭签字
document.getElementById("save").onclick = function(){
isSign = !isSign
if (isSign){
//开始签名
// console.log("开始签名");
document.getElementById("save").innerText = "保存";
}else{
//保存,生成png图片
// console.log("保存");
document.getElementById("save").innerText = "重新";
download(draw.toDataURL(),"签名.png");
//设置初始值
isEraser = false;//关闭橡皮擦
}
}
在上面download(draw.toDataURL(),"签名.png")
保存后调用download下载方法,并传入了canvas当前画部的数据和导出名字draw.toDataURL()
是获取一个base64的图片数据,这时如何进行下载?可以通过调用a
标签实现图片下载。
js
//封装a标签下载组件
function download(data64, fileName) {
console.log();
let a = document.createElement("a");
a.href = data64;
a.download = fileName;
//将a标签添加在页面上
document.body.append(a);
//下载
a.click();
//下载完成移除a标签
a.remove();
}
4 清空画布
清空画布主要调用画笔的clearRect
方法,他可以清空指定区域的内容。只需要设置好坐标位置即可。
js
//清空画布内容
document.getElementById("anew").onclick = function(){
if (!isSign) return;
//清空画布先结束之前操作
context2.closePath()
console.log("清空画布内容");
context2.clearRect(0,0,width,height);
context2.beginPath();
//设置橡皮擦
isEraser = false;
drawEvent();
}
5 橡皮擦·
由于之前封装好了画笔事件,现在只需要改变isEraser
状态,并重新调用画笔事件drawEvent()
。
js
//橡皮擦功能
document.getElementById("eraser").onclick = function(){
if (!isSign) return;
isEraser =!isEraser;
//重新调用画笔事件
drawEvent();
}
6 最终效果
四、图板涂抹截取
这个demo主要是想实现涂抹某个区域然后对其进行截取为单独图片,他的难点在于理解canvas画笔每个坐标点位与像素的之间关系,和透明颜色相关知识。
1 透明颜色概念
透明的含义是"看得透"。在计算机图形学中,透明通常用来描述某一部分的图像或者界面是可以看透的。例如,我们可以使用透明效果来实现深色图像的遮盖以及透视效果的创建。
透明度通常用一个0到1之间的实数值来表示,0表示完全透明,1表示完全不透明。
理解RGB色彩模式
RGB色彩模式是一种基于三原色的表示法,其中R表示红色,G表示绿色,B表示蓝色。通过混合不同比例的三原色,可以得到不同的颜色。透明度通常由一个透明度值表示,这个值也是一个0到1的实数。
下面是一个使用RGB表示法表达透明颜色的例子:
css
background: rgba(255, 0, 0, 0.5);
在上面的例子中,我们使用rgba()函数来表示一个透明度为0.5的红色背景。其中,"a"表示alpha channel,也就是透明度通道。
用刚才导出图片为例子,可以看出透明区域的rgba和写了文字的rgba是通过最后一个a
值判断,透明区域的rgba(0,0,0,0)
而有文字区域rgba(0,0,0,1)
可以明确一点最后一个值肯定 a>0
2 涂抹截取原理
涂抹截取原理原理主要是两步: 第一步设置一张背景和一个canvas,在canvas上面涂抹会生成一个图像数组,这个图像数据会记录下每个rgba点位信息。 第二步对比,将img图片中的每个像素点和canvas上的比较,如果canvas上的点位不为空,则保留img图片上的像素点,这样得到一个新的图像数组,将其导出到另外地方可以看到效果。
3 实现代码
1、初始化
先声明两个div,一个用来操作实现【涂抹】【重置】【橡皮擦】功能,另一个则点击【导出】展示最终结果。
html
<div>
<div class="shear">
<div>
<button id="derive">导出</button>
<button id="dedaub">涂抹</button>
<button id="shanew">重置</button>
<button id="sheraser">橡皮擦</button>
</div>
</div>
</div>
<div>
<div class="prectemp">
<div style="height: 22.81px;">
截取涂抹内容
</div>
<div id="sheartemp">
</div>
</div>
</div>
按照电子签字组件实现逻辑先声明两个变量保存是否开启涂抹状态、是否开启橡皮擦和宽度高度等基本信息。
js
/**
* 涂抹截取
* 1、创建图片作为背景;
*
*/
var isDaub = false;// 是否开启涂抹状态
var isErase = false;//是否开启橡皮擦
const width = 400;
const height = 300;
创建一个img图层放在页面class为shear的位置上,同时创建canvas图层也放在页面class为shear的位置上。
js
const img = document.createElement("img");
img.src = "./21092414350ML0-0-lp-350.jpg";
img.classList.add("daub");
img.width =width;
img.height = height-30;
document.getElementsByClassName("shear")[0].appendChild(img);
const daub = document.createElement("canvas");
daub.classList.add("daub");
daub.width = width;
daub.height = height-30;
document.getElementsByClassName("shear")[0].appendChild(daub);
设置画笔基本属性,因为这次是在img上涂抹,所以需要将画笔颜色设置为半透明,这样才不会完全遮盖图片context4.strokeStyle = "rgb(232 149 38/ 50%)
。
js
//2d画笔
var context4 = daub.getContext('2d');
context4.lineCap = "round";
context4.lineJoin = "round";
context4.lineWidth = 20;
context4.strokeStyle = "rgb(232 149 38/ 50%)"; //设置透明渡的颜色选取内容
2、鼠标事件
这里涂抹是橡皮擦实现原理和签字组件类似,封装一个画笔事件drawEvent()
,之前通过组件的onmousedown
、onmousemove
、onmouseup
实现:1、按下鼠标左键;2、移动鼠标;3、抬起鼠标左键的事件监听,使用方法如常用的onclick
一样。 根据两个状态,isDaub
(是否开启涂抹状态)、isErase
(是否开启橡皮擦)通过这两个状态来控制是否清除画布。 最后鼠标抬起,则清空鼠标移动和抬起事件,当用户再次按下鼠标则再次循环执行该事件,具体实现可以看下列详细代码。
js
/**
* 涂抹/橡皮擦事件
*
*/
daubEvent();
function daubEvent() {
daub.onmousedown = function(event) {
if (!isDaub) return;
// 开始新的路径或继续现有路径
if (isErase) {
context4.globalCompositeOperation = 'destination-out';
}else{
context4.globalCompositeOperation = 'source-over';
}
context4.beginPath();
context4.moveTo(event.offsetX,event.offsetY);
daub.onmousemove = function(event) {
if (isErase) {
// 设置橡皮擦粗细
context4.lineWidth = 20; //设置字体10号
context4.strokeStyle = "rgba(0, 0, 0, 1)";
context4.globalAlpha = 1;
}else{
context4.strokeStyle = "rgb(232 149 38/ 75%)"; //设置透明渡的颜色选取内容
context4.lineWidth = brushSize; //设置字体10号
context4.globalAlpha = 0.01;
}
context4.lineTo(event.offsetX,event.offsetY);
context4.stroke();
}
daub.onmouseup = function(event) {
daub.onmousemove = null;
daub.onmouseup = null;
}
}
}
涂抹、重置、橡皮擦功能同样和电子签字一致,由于刚才已经封装了点击事件,只需要通过控制isDaub和isErase两个状态来管理画布如何绘画。
js
//点击【开始】可以进行涂抹
document.getElementById("dedaub").onclick = function(){
isDaub = !isDaub
if (isDaub){
document.getElementById("dedaub").innerText = "停止";
}else{
document.getElementById("dedaub").innerText = "涂抹";
isErase = false;//关闭橡皮擦
}
}
//点击【重置】清空画布内容
document.getElementById("shanew").onclick = function(){
if (!isDaub) return;
//清空画布先结束之前操作
context4.closePath()
context4.clearRect(0,0,width,height);
context4.beginPath();
//设置橡皮擦
isErase = false;
daubEvent();
}
//点击【橡皮擦】可以进行橡皮擦
document.getElementById("sheraser").onclick = function(){
if (!isDaub) return;
isErase =!isErase
if (isErase){
document.getElementById("sheraser").innerText = "画笔";
}else{
document.getElementById("sheraser").innerText = "橡皮擦";
}
console.log("橡皮擦",isErase);
daubEvent();
}
3、导出图片
js
//点击【导出】创建一张图片,循环图片rgb不透明的点,将原图内容放在这个位置
document.getElementById("derive").onclick = function(){
console.log(document.querySelector("#newCanvas"));
//判断是否生成过导出结果,存在则移除
document.querySelector("#newCanvas") && document.querySelector("#newCanvas").remove();
//调用contrast方法重新生成导出结果
contrast();
}
将img按照canvas结果进行重新绘制需要裁切以下步骤:
- 获取img图片、canvas图层
- 创建一个新的canvas图层
newcanvas
,声明一个newcontext
新图层,画笔将img绘制在上面 - 获取旧的canvas图层像素转成rgba的数组
context4.getImageData(0, 0, width, height).data
- 通过canvas图层长宽进行循环,可以得到每个像素点
- 由于每个像书点包含四个元素:红色通道 、绿色通道 、蓝色通道 、透明度 ,所以可以计算出每个点位的rgba值下标
index = (y * width + x) * 4;
- 判断像素是否为主体区域(透明度大于0),如果等于0则设置为透明颜色。
- 最终完成
newcanvas
渲染到页面上,实现图片根据涂抹内容裁剪渲染
js
/**
* 根据图层点位,将图片内容绘制到新的canvas上
* text4data 旧图层的内容 (用户涂抹所有内容,即rgb不透明)获取所有像素的
* newCanvas 创建新的图层
* newcontext 新图层画笔
* 1、新图层newcontext引入需要裁剪的图片
* 2、图片加载完成,循环旧图层每个像素点,
* 3、判断text4data旧图层像素的是否透明,如果透明则将新图层对应内容区域也修改透明
*/
function contrast() {
const text4data = context4.getImageData(0, 0, width, height).data;
// 创建一个新的canvas图层
const newCanvas = document.createElement("canvas");
newCanvas.id = "newCanvas";
const newcontext = newCanvas.getContext('2d');
// 设置Canvas的大小与图片一致
newCanvas.width = width;
newCanvas.height = height-30;
const newimg = new Image();
newimg.src = "./21092414350ML0-0-lp-350.jpg";
// 将图片绘制到Canvas上
newcontext.drawImage(newimg, 0, 0,width,height);
const imageData = newcontext.getImageData(0, 0, width, height);
const newdata = imageData.data;
newimg.onload = function () {
//循环每个像素点,如果是白色则 将其设为透明
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const index = (y * width + x) * 4;
const text4a = text4data[index + 3];
// 判断像素是否为主体区域(透明度大于0)
if (text4a > 0 ) {
// const r = newdata[index];
// const g = newdata[index + 1];
// const b = newdata[index + 2];
// const a = newdata[index + 3];
}else{
newdata[index] = 0; // 红色通道
newdata[index + 1] = 0; // 绿色通道
newdata[index + 2] = 0; // 蓝色通道
newdata[index + 3] = 0; // 透明度
}
}
}
// newdata = newcontext.getImageData(0, 0, width, height).putImageData(tempDate);
newcontext.putImageData(imageData, 0, 0);
}
document.getElementById("sheartemp").appendChild(newCanvas);
}