canvas实现动态替换人物的背景颜色
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
起因今天遇见一个特别有意思的小功能。 就是更换人物图像的背景颜色。大致操作步骤就是:点击人物-实现背景颜色发生变化 将图片绘画到canvas画布上我们需要将图片绘制到canvas画布上。 这样做的目的是为了方便我们去操作像素点来更改颜色。 首先创建 Image 的实例。将图片的地址赋值给图片实例src。 当图片加载完成后,onload 事件可以知道图片是否加载完成 根据 Image的实例将图片大小赋值给画布,让他们大小保持一致。 最后使用 ctx.drawImage来进行绘画就行 特别提醒的是:src 属性一定要写到 onload 的后面,否则程序在 IE 中会出错。 <body> <canvas id="canvas"> </body> <script type="text/javascript"> // 获取dom节点 const canvas = document.getElementById('canvas') //获取上下文 const ctx = canvas.getContext('2d'); // 将图片绘制到canvas画布上 function initPic(picInfo){ // 创建一个图片的实例 const img = new Image() // 引入图片的地址 img.src = picInfo.url img.onload =()=>{ // 设置画布的宽高与图片的保持一致 canvas.width= img.width canvas.height= img.height // 开始绘画 ctx.drawImage(img, 0, 0 ); } } initPic({ url: './src/assets/person.png' }) </script> drawImage 的简单介绍canvas的drawImage()提供了更多在canvas上绘制图像的方法。drawImage() 方法有三种形式:drawImage(image, dx, dy) 在指定的 (dx, dy) 位置绘制图像。drawImage(image, dx, dy, width, height) 在指定的 (dx, dy) 位置,并使用指定的宽度和高度绘制图像。drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, dx, dy, width, height) 在指定的 (dx, dy) 位置,并使用指定的宽度和高度绘制图像。图像的源坐标和尺寸也指定了。 image:允许任何的画布图像源 注册事件获取点击时的坐标对应的颜色我们通过 e.offsetX, e.offsetY 可以轻松拿到点击的坐标x,y。 可以通过 getImageData 获取到图片的所有像素点的颜色。 但是怎么通过点击的位置(x,y)获取到对应的的像素索引呢? 其实他们的关系是这样的:// 每个像素占用4个字节(RGBA)const index = (y * image.width + x) * 4; 根据上面这个公式,我们可以知道坐标对应的像素索引。 有了索引,我们可以拿到坐标对应的颜色 function clickMy(e){ // 获取点击时的坐标 let x = e.offsetX let y = e.offsetY // 获取所有的像素点颜色 let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height); console.log('获取所有的像素点颜色', imagedata) // 这个坐标点对应的颜色 let clickColor = getColor(x,y, imagedata) console.log('这个坐标点对应的颜色', clickColor) }// 计算点击坐标对应的像素索引 function bgIndex(x,y){ return (y * canvas.width + x) * 4; }// 根据索引得到颜色值function getColor(x,y,imgData){ let i = bgIndex(x,y) return [ imgData.data[i], imgData.data[i+1], imgData.data[i+2], imgData.data[i+3] ] }// 注册事件canvas.addEventListener("click", clickMy, false) 更改当前像素点的颜色现在我们希望点击的这个点的颜色变成红色。 现在的我们可以拿到所有像素点,当前的坐标,坐标对应的颜色。 现在我们的主角出场了(此时灯光闪烁,五彩的光打在他的身上) context.putImageData(imageData, x, y); 第1个参数:imageData: 包含了图像的所有像素数据, 通过ctx.getImageData(0, 0, canvas.width, canvas.height)可以获取到; 第2,3个参数表示坐标。 它用于将图像数据绘制到画布上。 这个方法允许开发者操作和绘制像素级别的数据, 从而实现复杂的图像效果和处理。 function clickMy(e){ // 获取点击时的坐标 let x =e.offsetX let y = e.offsetY // 获取所有的像素点颜色 let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height); console.log('获取所有的像素点颜色', imagedata) // 这个坐标点对应的颜色 let clickColor = getColor(x,y, imagedata) console.log('这个坐标点对应的颜色', clickColor) // 最后更改为红色的rgba值 let targetBgArr = [255,0,0,255] // 更改颜色 function changeColor(x,y){ let i = bgIndex(x,y) imagedata.data.set(targetBgArr, i) } changeColor(x,y) // 更改当前像素点的颜色 ctx.putImageData(imagedata, 0, 0); } 将被点击的点的相似颜色全部变为红色我们通过两个颜色的rgba值相减,看rgba的各个绝对值之和。 来判断颜色的相似。 同时我页需要注意边界范围与颜色已经变为了目标颜色。 这个时候我们就需要停止调用函数了 核心代码<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <canvas id="canvas"> </body> <script type="text/javascript"> // 获取dom节点 const canvas = document.getElementById('canvas') // 获取上下文 const ctx = canvas.getContext('2d',{ willReadFrequently:true }); function initPic(picInfo){ // 创建一个图表的实例 const img = new Image() img.onload =()=>{ // 设置画布的宽高与图片的保持一致 canvas.width= img.width canvas.height= img.height // 开始绘画 ctx.drawImage(img, 0, 0 ); } // 引入图片的地址 img.src = picInfo.url } function clickMy(e){ // 获取点击时的坐标 let x =e.offsetX let y = e.offsetY // 获取所有的像素点颜色 let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height); console.log('获取所有的像素点颜色', imagedata) // 这个坐标点对应的颜色 let clickColor = getColor(x,y, imagedata) console.log('这个坐标点对应的颜色', clickColor) // 最后更改为红色的rgba值 let targetBgArr = [255,0,0,255] function changeColor(x,y){ // 边界范围 if(x<0 || x>canvas.width || y<0 || y>canvas.height){ return } let color = getColor(x,y,imagedata ) // 相似颜色的相差值 if(diffBg(color,clickColor)>150){ return } // 已经变为了目标色(红色) if(diffBg(color,targetBgArr)==0){ return } let i = bgIndex(x,y) // 在内存中更改像素的颜色 imagedata.data.set(targetBgArr, i) // 改变周围(上下左右)的颜色 changeColor(x+1,y) changeColor(x-1,y) changeColor(x,y+1) changeColor(x,y-1) } changeColor(x,y) // 将内存中的像素点的颜色(重新绘制在画布上) ctx.putImageData(imagedata, 0, 0); } // 计算点击坐标对应的像素索引 function bgIndex(x,y){ return (y * canvas.width + x) * 4; } // 根据索引得到颜色值 function getColor(x,y,imgData){ let i = bgIndex(x,y) return [ imgData.data[i], imgData.data[i+1], imgData.data[i+2], imgData.data[i+3] ] } // 查看两个颜色的相差值 function diffBg(color1,color2){ // 我们是取两个颜色的绝对值相加 return Math.abs(color1[0] -color2[0]) + Math.abs(color1[1] -color2[1]) + Math.abs(color1[2] -color2[2]) + Math.abs(color1[3] -color2[3]) } // 注册事件 canvas.addEventListener("click", clickMy, false) initPic({ url: '../assets/person1.png' }) </script></html> 更改为按钮,背景发生改变上面我们实现了,点击背景色,实现颜色的更改。 但是实际的过程中。 我们是不知道背景颜色的,怎么去确认背景颜色呢? 其实,可以默认坐标为(4,4)是背景颜色。 在实际的过程中,其实这个位置99.9999%是背景色。 我们是先选择颜色,然后点击确定,实现颜色的更改 现在我们来优化一下。让用户自己选择背景色,选择好后。 点击确定,背景颜色就发生变化 <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> </style></head><body> <div> <canvas id="canvas"> </div> <input type="color" id="color" > <button id="red">确定</button> </body> <script type="text/javascript"> // 获取dom节点 const canvas = document.getElementById('canvas') // 获取上下文 const ctx = canvas.getContext('2d',{ willReadFrequently:true }); // 将16进制转化为rgba的颜色值 function changeRGBA(hex) { // 去除 # 开头的第一个字符 hex = hex.slice(1); // 将16进制字符串转换rgba let rgba = []; for (let i = 0; i < 6; i += 2) { let byte = parseInt(hex.substr(i, 2), 16); rgba.push(byte); } // 添加 alpha 通道 rgba.push(255); // 返回 RGBA 颜色值 return rgba; } function initPic(picInfo){ // 创建一个图表的实例 const img = new Image() img.onload =()=>{ // 设置画布的宽高与图片的保持一致 canvas.width= img.width canvas.height= img.height // 开始绘画 ctx.drawImage(img, 0, 0 ); } // 引入图片的地址 img.src = picInfo.url } function clickMy(e, type){ let color = document.getElementById('color') // 4,4的地方默认为是背景颜色 let x = 4 let y = 4 // 获取所有的像素点颜色 let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height); // 这个坐标点对应的颜色 let clickColor = getColor(x,y, imagedata) console.log('这个坐标点对应的颜色', clickColor) // 颜色为用户选择的值 let targetBgArr = changeRGBA(color.value) function changeColor(x,y){ // 边界范围 if(x<0 || x>canvas.width || y<0 || y>canvas.height){ return } let color = getColor(x,y,imagedata ) // 相似颜色的相差值 if(diffBg(color,clickColor)>150){ return } // 已经变为了目标色(红色) if(diffBg(color,targetBgArr)==0){ return } let i = bgIndex(x,y) // 在内存中更改像素的颜色 imagedata.data.set(targetBgArr, i) // 改变周围(上下左右)的颜色 changeColor(x+1,y) changeColor(x-1,y) changeColor(x,y+1) changeColor(x,y-1) } changeColor(x,y) // 将内存中的像素点的颜色(重新绘制在画布上) ctx.putImageData(imagedata, 0, 0); } // 计算点击坐标对应的像素索引 function bgIndex(x,y){ return (y * canvas.width + x) * 4; } // 根据索引得到颜色值 function getColor(x,y,imgData){ let i = bgIndex(x,y) return [ imgData.data[i], imgData.data[i+1], imgData.data[i+2], imgData.data[i+3] ] } // 查看两个颜色的相差值 function diffBg(color1,color2){ // 我们是取两个颜色的绝对值相加 return Math.abs(color1[0] -color2[0]) + Math.abs(color1[1] -color2[1]) + Math.abs(color1[2] -color2[2]) + Math.abs(color1[3] -color2[3]) } // 注册事件 canvas.addEventListener("click", clickMy, false) red.addEventListener("click", clickMy, false) initPic({ url: '../assets/person1.png' }) </script></html> 最后的功能-下载上面我们已经成功实现让用户选择颜色。 更换用户自己选择的颜色。 下载我们只需要实现下载功能就好了。 下载功能主要使用 canvas.toDataURL 然后利用a标签进行下载 <button id="down">下载</button> down.addEventListener('click',()=>{ let imgURL = canvas.toDataURL({format: "image/png", quality:1, width:canvas.width, height:canvas.height}); let link = document.createElement('a'); link.download = "人物图片"; link.href = imgURL; document.body.appendChild(link); link.click(); document.body.removeChild(link); }) 遇见问题,这是你成长的机会,如果你能够解决,这就是收获。该文章在 2023/11/27 15:27:55 编辑过 |
关键字查询
相关文章
正在查询... |