canvas實現(xiàn)動態(tài)替換人物的背景顏色
當前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
起因今天遇見一個特別有意思的小功能。 就是更換人物圖像的背景顏色。大致操作步驟就是:點擊人物-實現(xiàn)背景顏色發(fā)生變化 將圖片繪畫到canvas畫布上我們需要將圖片繪制到canvas畫布上。 這樣做的目的是為了方便我們?nèi)ゲ僮飨袼攸c來更改顏色。 首先創(chuàng)建 Image 的實例。將圖片的地址賦值給圖片實例src。 當圖片加載完成后,onload 事件可以知道圖片是否加載完成 根據(jù) Image的實例將圖片大小賦值給畫布,讓他們大小保持一致。 最后使用 ctx.drawImage來進行繪畫就行 特別提醒的是:src 屬性一定要寫到 onload 的后面,否則程序在 IE 中會出錯。 <body> <canvas id="canvas"> </body> <script type="text/javascript"> // 獲取dom節(jié)點 const canvas = document.getElementById('canvas') //獲取上下文 const ctx = canvas.getContext('2d'); // 將圖片繪制到canvas畫布上 function initPic(picInfo){ // 創(chuàng)建一個圖片的實例 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)獲取到對應的的像素索引呢? 其實他們的關(guān)系是這樣的:// 每個像素占用4個字節(jié)(RGBA)const index = (y * image.width + x) * 4; 根據(jù)上面這個公式,我們可以知道坐標對應的像素索引。 有了索引,我們可以拿到坐標對應的顏色 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; }// 根據(jù)索引得到顏色值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) 更改當前像素點的顏色現(xiàn)在我們希望點擊的這個點的顏色變成紅色。 現(xiàn)在的我們可以拿到所有像素點,當前的坐標,坐標對應的顏色。 現(xiàn)在我們的主角出場了(此時燈光閃爍,五彩的光打在他的身上) context.putImageData(imageData, x, y); 第1個參數(shù):imageData: 包含了圖像的所有像素數(shù)據(jù), 通過ctx.getImageData(0, 0, canvas.width, canvas.height)可以獲取到; 第2,3個參數(shù)表示坐標。 它用于將圖像數(shù)據(jù)繪制到畫布上。 這個方法允許開發(fā)者操作和繪制像素級別的數(shù)據(jù), 從而實現(xiàn)復雜的圖像效果和處理。 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); } 將被點擊的點的相似顏色全部變?yōu)榧t色我們通過兩個顏色的rgba值相減,看rgba的各個絕對值之和。 來判斷顏色的相似。 同時我頁需要注意邊界范圍與顏色已經(jīng)變?yōu)榱四繕祟伾? 這個時候我們就需要停止調(diào)用函數(shù)了 核心代碼<!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節(jié)點 const canvas = document.getElementById('canvas') // 獲取上下文 const ctx = canvas.getContext('2d',{ willReadFrequently:true }); function initPic(picInfo){ // 創(chuàng)建一個圖表的實例 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 } // 已經(jīng)變?yōu)榱四繕松?紅色) if(diffBg(color,targetBgArr)==0){ return } let i = bgIndex(x,y) // 在內(nèi)存中更改像素的顏色 imagedata.data.set(targetBgArr, i) // 改變周圍(上下左右)的顏色 changeColor(x+1,y) changeColor(x-1,y) changeColor(x,y+1) changeColor(x,y-1) } changeColor(x,y) // 將內(nèi)存中的像素點的顏色(重新繪制在畫布上) ctx.putImageData(imagedata, 0, 0); } // 計算點擊坐標對應的像素索引 function bgIndex(x,y){ return (y * canvas.width + x) * 4; } // 根據(jù)索引得到顏色值 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> 更改為按鈕,背景發(fā)生改變上面我們實現(xiàn)了,點擊背景色,實現(xiàn)顏色的更改。 但是實際的過程中。 我們是不知道背景顏色的,怎么去確認背景顏色呢? 其實,可以默認坐標為(4,4)是背景顏色。 在實際的過程中,其實這個位置99.9999%是背景色。 我們是先選擇顏色,然后點擊確定,實現(xiàn)顏色的更改 現(xiàn)在我們來優(yōu)化一下。讓用戶自己選擇背景色,選擇好后。 點擊確定,背景顏色就發(fā)生變化 <!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節(jié)點 const canvas = document.getElementById('canvas') // 獲取上下文 const ctx = canvas.getContext('2d',{ willReadFrequently:true }); // 將16進制轉(zhuǎn)化為rgba的顏色值 function changeRGBA(hex) { // 去除 # 開頭的第一個字符 hex = hex.slice(1); // 將16進制字符串轉(zhuǎn)換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){ // 創(chuàng)建一個圖表的實例 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 } // 已經(jīng)變?yōu)榱四繕松?紅色) if(diffBg(color,targetBgArr)==0){ return } let i = bgIndex(x,y) // 在內(nèi)存中更改像素的顏色 imagedata.data.set(targetBgArr, i) // 改變周圍(上下左右)的顏色 changeColor(x+1,y) changeColor(x-1,y) changeColor(x,y+1) changeColor(x,y-1) } changeColor(x,y) // 將內(nèi)存中的像素點的顏色(重新繪制在畫布上) ctx.putImageData(imagedata, 0, 0); } // 計算點擊坐標對應的像素索引 function bgIndex(x,y){ return (y * canvas.width + x) * 4; } // 根據(jù)索引得到顏色值 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> 最后的功能-下載上面我們已經(jīng)成功實現(xiàn)讓用戶選擇顏色。 更換用戶自己選擇的顏色。 下載我們只需要實現(xiàn)下載功能就好了。 下載功能主要使用 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 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |