應(yīng)用場景:在很多時(shí)候,前端開發(fā)過程中需要?jiǎng)討B(tài)的獲取圖片的主要的顏色值,并根據(jù)主色調(diào)去調(diào)整主題樣式的顏色或者模擬出一套配色方案,如圖

根據(jù)圖片,模擬出一套主題配色方案。

實(shí)現(xiàn)及原理:以canvas的getImageData()方法為基礎(chǔ),以像素顏色的計(jì)算為核心。
????????我們把一個(gè)img標(biāo)簽,放入到canvas當(dāng)中去,然后使用getImageData方法來獲取像素信息:
部分代碼:

????????在控制臺(tái)中我們可以看到很多數(shù)組,對(duì)于這張圖來說他是有規(guī)律的,每四個(gè)為一組,每一組為一圖片中的一個(gè)像素塊,比如下標(biāo)0,1,2,3分別代表著raba()中的r,g,b,a。a代表這塊像素中的透明度

教學(xué)圖片:
????????在這里我做了一張圖片方便大家理解,如果我們將每一個(gè)由rgba組成的像素塊理解為圖片中的一個(gè)點(diǎn),那么由width和height(即x坐標(biāo)和y坐標(biāo))內(nèi)的像素點(diǎn)就能組成一個(gè)完整的圖片的一面。
?????? 那么rgba中的a也是不可或缺的一部分,我們可以理解為透明度是圖片構(gòu)成中的z坐標(biāo),比如在獲取npg透明背景圖片的主色調(diào)的時(shí)候,不得不考慮背景透明的地方的處理。

二維的實(shí)現(xiàn)——平均值算法(獲取主色調(diào)):
????????在平面坐標(biāo)系中(不考慮透明度的情況下)即只有rgb,我們可以使用canvas的getImageData函數(shù)獲取所有像素的數(shù)據(jù),然后將所有的rgb三值各取平均值即可。
<!DOCTYPEhtml><htmllang="en"><head>??? <meta charset="UTF-8" />??? <title>1234</title></head><body><canvasid="myCanvas"></canvas><imgid="imgs" src="" width='422'></img>?<spanstyle='display: inline-block;width:100px;height: 100px;' id='span'>12</span><spanstyle='display: inline-block;width:100px;height: 100px;' id='span1'>112</span></body><script>??? varcanvas=document.getElementById('myCanvas');??? var img=document.getElementById('imgs');??? var span=document.getElementById('span');????? function getImageColor(canvas, img) {??????? canvas.width = img.width;??????? canvas.height = img.height;???????? var context =canvas.getContext("2d");???????? context.drawImage(img, 0,0,canvas.width,canvas.height);???????? // 獲取像素?cái)?shù)據(jù)??????? var data = context.getImageData(0, 0,img.width, img.height).data;??????? console.log(data)??????? var r=1,g=1,b=1;??????? // 取所有像素的平均值??????? for (var row = 0; row < img.height;row++) {??????????? for (var col = 0; col <img.width; col++) {??????? // console.log(data[((img.width * row)+ col) * 4])??????????????? if(row==0){??????????????????? r += data[((img.width *row) + col)];??????????????????? g += data[((img.width *row) + col) + 1];??????????????????? b += data[((img.width *row) + col) + 2];??????????????? }else{??????????????????? r += data[((img.width *row) + col) * 4];??????????????????? g += data[((img.width *row) + col) * 4 + 1];??????????????????? b += data[((img.width *row) + col) * 4 + 2];??????????????? }?????? ?????}??????? }???????? console.log(r,g,b)??????? // 求取平均值??????? r /= (img.width * img.height);??????? g /= (img.width * img.height);??????? b /= (img.width * img.height);???????? // 將最終的值取整??????? r = Math.round(r);??????? g = Math.round(g);??????? b = Math.round(b);??????? console.log(r,g,b)??????? span.style.background ="rgb(" + r + "," + g + "," + b + ")"??????? return "rgb(" + r +"," + g + "," + b + ")";??? }??? getImageColor(canvas,img)?</script></html>

????????以上方法缺點(diǎn)在于:無法計(jì)算透明背景的主色調(diào),主色調(diào)會(huì)被png圖片透明區(qū)域的大小所影響。優(yōu)點(diǎn)就是簡單明了,方便快捷。
三維坐標(biāo)實(shí)現(xiàn)——中位切分法(可準(zhǔn)確獲取png圖片的主色調(diào)):
????????中位切分算法的原理很簡單直接,將圖像顏色看作是色彩空間中的長方體(VBox),從初始整個(gè)圖像作為一個(gè)長方體開始,將RGB中最長的一邊從顏色統(tǒng)計(jì)的中位數(shù)一切為二,使得到的兩個(gè)長方體所包含的像素?cái)?shù)量相同,重復(fù)上述步驟,直到最終切分得到長方體的數(shù)量等于主題顏色數(shù)量為止。
所以這里就不去大篇幅的解釋如何實(shí)現(xiàn)的,直接獻(xiàn)上插件。插件下載地址:插件下載
插件使用方法:
引入插件并且使用:
//html中代碼
var b = new ColorThief();
var c = b.getColor(imgs,10,10);
var c = b.getColorAsync(imgs.src,asd,10)//第一個(gè)參數(shù)是圖片src,第二個(gè)參數(shù)是自定義的回調(diào)函數(shù),第三個(gè)參數(shù)是質(zhì)量,質(zhì)量越大計(jì)算越粗糙
//html中回調(diào)函數(shù)
function asd(data,elementImg){
???console.log('zhuR',data)
???/*data對(duì)象中
???*MainColoruse表示圖片的主色調(diào)
???*Embellish圖片配色方案
??? *Complementary圖片互補(bǔ)色,大多用于設(shè)置字體顏色與背景突出顯示。
???*/
???console.log(elementImg)
}

效果1:這里有一張npg透明背景的圖片,經(jīng)計(jì)算不會(huì)將npg透明的背景計(jì)算在內(nèi)。



效果2:一張照片的配色方案。


插件下載地址:插件下載