這篇文章給大家分享的是有關(guān)JavaScript純色二維碼變成彩色二維碼的示例分析的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
成都創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站建設(shè)、網(wǎng)站設(shè)計、寧鄉(xiāng)網(wǎng)絡(luò)推廣、小程序制作、寧鄉(xiāng)網(wǎng)絡(luò)營銷、寧鄉(xiāng)企業(yè)策劃、寧鄉(xiāng)品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供寧鄉(xiāng)建站搭建服務(wù),24小時服務(wù)熱線:028-86922220,官方網(wǎng)址:muchs.cn
前置知識
drawImage方法可以把圖片畫到canvas上,getImageData方法可以獲得一個矩形區(qū)域所有像素點的信息,返回值的data屬性是一個一維數(shù)組,儲存了所有像素點的信息,一個像素點的信息會占四個元素,分別代表r,g,b和透明度。而像素點在一維數(shù)組中的順序是從左到右,從上到下。最后就是putImageData方法,把更改過的像素信息數(shù)組重新扔回畫布上。
一些小坑
第一個坑就是canvas用屬性去給寬高,別用css;
第二個坑,做圖片處理好像得服務(wù)器環(huán)境,本地是不行的,聽說是基于什么安全考慮,最后我是通過搭本地服務(wù)器解決了canvas的報錯。
第三個坑,棧溢出,這個目前還沒找到原因,后面會詳細講
變色的思路
主要思路來自于《啊哈!算法!》里面深度優(yōu)先搜索和廣度優(yōu)先搜索的章節(jié),該章節(jié)的最后一部分的“寶島探險”實現(xiàn)了給不同的區(qū)域依次編號,把編號看成染色,其實是一樣的。
具體實現(xiàn)
其實所謂的彩色二維碼,不是那種每個像素點顏色隨機的二維碼。仔細觀察二維碼就會發(fā)現(xiàn),黑色的部分是一塊一塊的,他們分布在白色當(dāng)中,就好像島嶼分布在海里,我們要做的就是把每個黑色塊單獨染色。黑色塊的實質(zhì)就是一個一個黑色的像素點。
前面也提到,我們使用canvas是因為可以進行像素操作,所以我們的操作其實是給像素點染色,我們顯然不希望給背景色染色,所以背景色需要進行一個判斷;前面也提到,背景色好像海洋分割了黑色的顏色塊,那也就是說我們讀一個像素點進行染色之后,不停的判斷它右側(cè)的像素點顏色,當(dāng)出現(xiàn)背景色的時候就說明到達了邊界,可以停止右方向的染色,但是每個像素點其實有四個相連接的方向,當(dāng)一個像素點右邊就是背景色,我們應(yīng)該也去嘗試別的方向的可能性,這個就是深度優(yōu)先搜索,通過遞歸,不斷的驗證當(dāng)前像素點的下一個位置的顏色,是背景色,那就回來,嘗試別的方向;不是背景色,那就染色,然后對染色之后的這個像素點進行四個方向的驗證。
有幾點提一下,判斷是不是背景色,肯定得比對rgba的值,所以顏色參數(shù)得做處理,另一個就是像素點信息的數(shù)組,每四個元素代表一個像素,所以想要比對正確的像素信息,這部分也要處理。
可能說的有點亂,我們看一下代碼
第一部分,canvas
// canvas 部分 var canvas = $("canvas")[0]; var ctx = canvas.getContext("2d"); var img = new Image(); img.src = path; //這里的path就是圖片的地址
第二部分,顏色的處理
// 分離顏色參數(shù) 返回一個數(shù)組 var colorRgb = (function() { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; return function(str) { var sColor = str.toLowerCase(); if (sColor && reg.test(sColor)) { if (sColor.length === 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } //處理六位的顏色值 var sColorChange = []; for (var i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } return sColorChange; } else { var sColorChange = sColor.replace(/(rgb\()|(\))/g, "").split(",").map(function(a) { return parseInt(a); }); return sColorChange; } } })();
第三部分,給初始參數(shù)
為了避免多余的操作,我們用一個標記數(shù)組來記錄判斷過的位置
// 參數(shù) var bg = colorRgb("#fff"); //忽略的背景色 var width = 220; var height = 220; var imgD; //預(yù)留給 像素信息 var colors = ["#368BFF", "#EF2767", "#F17900", "#399690", "#5aa6f7", "#fd417e", "#ffc000", "#59b6a6"]; //染色數(shù)組 // 隨機colors數(shù)組的一個序號 var ranNum = (function() { var len = colors.length; return function() { return Math.floor(Math.random() * len); } })(); // 標記數(shù)組 var book = []; for (var i = 0; i < height; i++) { book[i] = []; for (var j = 0; j < width; j++) { book[i][j] = 0; } }
第四部分,獲取像素信息,對每個像素點進行遍歷處理,最后扔回canvas
如果標記過,那就跳過,如果沒標記過,那就隨機一個顏色,深度優(yōu)先搜索并染色
img.onload = function() { ctx.drawImage(img, 0, 0, width, height); imgD = ctx.getImageData(0, 0, width, height); for (var i = 0; i < height; i++) { for (var j = 0; j < width; j++) { if (book[i][j] == 0 && checkColor(i, j, width, bg)) { //沒標記過 且是非背景色 book[i][j] = 1; var color = colorRgb(colors[ranNum()]); dfs(i, j, color); //深度優(yōu)先搜索 } } } ctx.putImageData(imgD, 0, 0); } // 驗證該位置的像素 不是背景色為true function checkColor(i, j, width, bg) { var x = calc(width, i, j); if (imgD.data[x] != bg[0] && imgD.data[x + 1] != bg[1] && imgD.data[x + 2] != bg[2]) { return true; } else { return false; } } // 改變顏色值 function changeColor(i, j, colorArr) { var x = calc(width, i, j); imgD.data[x] = colorArr[0]; imgD.data[x + 1] = colorArr[1]; imgD.data[x + 2] = colorArr[2]; } // 返回對應(yīng)像素點的序號 function calc(width, i, j) { if (j < 0) { j = 0; } return 4 * (i * width + j); }
關(guān)鍵代碼
我們通過一個方向數(shù)組,來簡化一下操作,我們約定好,嘗試的方向為順時針,從右邊開始。
// 方向數(shù)組 var next = [ [0, 1], //右 [1, 0], //下 [0, -1], // 左 [-1, 0] //上 ]; // 深度優(yōu)先搜索 function dfs(x, y, color) { changeColor(x, y, color); for (var k = 0; k <= 3; k++) { // 下一個坐標 var tx = x + next[k][0]; var ty = y + next[k][1]; //判斷越界 if (tx < 0 || tx >= height || ty < 0 || ty >= width) { continue; } if (book[tx][ty] == 0 && checkColor(tx, ty, width, bg)) { // 判斷位置 book[tx][ty] = 1; dfs(tx, ty, color); } } return; }
我遇到的最后一個坑就是當(dāng)長寬大于220時就會棧溢出,但是小于這個值就不會有問題,具體的原因還不清楚,猜測可能是判斷那里有問題,導(dǎo)致死循環(huán)了。
全部代碼在這里
// 分離顏色參數(shù) 返回一個數(shù)組 var colorRgb = (function() { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; return function(str) { var sColor = str.toLowerCase(); if (sColor && reg.test(sColor)) { if (sColor.length === 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } //處理六位的顏色值 var sColorChange = []; for (var i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } return sColorChange; } else { var sColorChange = sColor.replace(/(rgb\()|(\))/g, "").split(",").map(function(a) { return parseInt(a); }); return sColorChange; } } })(); // 驗證該位置的像素 不是背景色為true function checkColor(i, j, width, bg) { var x = calc(width, i, j); if (imgD.data[x] != bg[0] && imgD.data[x + 1] != bg[1] && imgD.data[x + 2] != bg[2]) { return true; } else { return false; } } // 改變顏色值 function changeColor(i, j, colorArr) { var x = calc(width, i, j); imgD.data[x] = colorArr[0]; imgD.data[x + 1] = colorArr[1]; imgD.data[x + 2] = colorArr[2]; } // 返回對應(yīng)像素點的序號 function calc(width, i, j) { if (j < 0) { j = 0; } return 4 * (i * width + j); } // 方向數(shù)組 var next = [ [0, 1], //右 [1, 0], //下 [0, -1], // 左 [-1, 0] //上 ]; // 深度優(yōu)先搜索 function dfs(x, y, color) { changeColor(x, y, color); for (var k = 0; k <= 3; k++) { // 下一個坐標 var tx = x + next[k][0]; var ty = y + next[k][1]; //判斷越界 if (tx < 0 || tx >= height || ty < 0 || ty >= width) { continue; } if (book[tx][ty] == 0 && checkColor(tx, ty, width, bg)) { // 判斷位置 book[tx][ty] = 1; dfs(tx, ty, color); } } return; } /*****上面為封裝的函數(shù)*****/ /***參數(shù)***/ var bg = colorRgb("#fff"); //忽略的背景色 var width = 220; var height = 220; var imgD; //預(yù)留給 像素信息數(shù)組 var colors = ["#368BFF", "#EF2767", "#F17900", "#399690", "#5aa6f7", "#fd417e", "#ffc000", "#59b6a6"]; //染色數(shù)組 // 隨機colors數(shù)組的一個序號 var ranNum = (function() { var len = colors.length; return function() { return Math.floor(Math.random() * len); } })(); // 標記數(shù)組 var book = []; for (var i = 0; i < height; i++) { book[i] = []; for (var j = 0; j < width; j++) { book[i][j] = 0; } } // canvas 部分 var canvas = $("canvas")[0]; var ctx = canvas.getContext("2d"); var img = new Image(); img.src = path; //這里的path就是圖片的地址 img.onload = function() { ctx.drawImage(img, 0, 0, width, height); imgD = ctx.getImageData(0, 0, width, height); for (var i = 0; i < height; i++) { for (var j = 0; j < width; j++) { if (book[i][j] == 0 && checkColor(i, j, width, bg)) { //沒標記過 且是非背景色 book[i][j] = 1; var color = colorRgb(colors[ranNum()]); dfs(i, j, color); //深度優(yōu)先搜索 } } } ctx.putImageData(imgD, 0, 0); }
總結(jié)
雖然看起來有點長,其實大部分函數(shù)都在處理像素點的信息。實現(xiàn)起來,主要就是得對深度優(yōu)先搜索有所了解,每個像素點都進行深度優(yōu)先搜索,染過色的自然被標記過,所以當(dāng)一個新的沒標記過的像素點出現(xiàn)時,自然意味著新的顏色塊。細節(jié)方面,就是注意一下imgD.data和像素點序號之間的對應(yīng)關(guān)系,別的也就還好了。不過注意一點就是,因為像素點很小,所以肉眼覺得不相連的色塊也有可能是連在一起的,會染成一樣的顏色。
忘了放圖了,這里放幾張,拿qq截的,把外面的邊框不小心也截了,嘛,湊活看看吧
感謝各位的閱讀!關(guān)于“JavaScript純色二維碼變成彩色二維碼的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
本文標題:JavaScript純色二維碼變成彩色二維碼的示例分析
文章源于:http://muchs.cn/article4/pjjjie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計、云服務(wù)器、品牌網(wǎng)站設(shè)計、用戶體驗、虛擬主機、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)