亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript純色二維碼變成彩色二維碼

 更新時(shí)間:2020年07月23日 11:46:53   作者:出世Sunny  
這篇文章主要為大家詳細(xì)介紹了JavaScript純色二維碼變成彩色二維碼的方案,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文章主要討論的是如何將一個(gè)純色二維碼變成彩色的。

前段時(shí)間公司業(yè)務(wù)上有這么一個(gè)需求,客戶(hù)不喜歡后臺(tái)生成的純色二維碼,純藍(lán),純紫,純綠都不行,想要彩色二維碼。然后這個(gè)任務(wù)都落到我頭上了,因?yàn)槭菆D片處理,那主要思路就是靠canvas,canvas可以進(jìn)行像素操作,所以我進(jìn)行了一些嘗試,也踩了一點(diǎn)小坑,具體記錄如下。

前置知識(shí)

drawImage方法可以把圖片畫(huà)到canvas上,getImageData方法可以獲得一個(gè)矩形區(qū)域所有像素點(diǎn)的信息,返回值的data屬性是一個(gè)一維數(shù)組,儲(chǔ)存了所有像素點(diǎn)的信息,一個(gè)像素點(diǎn)的信息會(huì)占四個(gè)元素,分別代表r,g,b和透明度。而像素點(diǎn)在一維數(shù)組中的順序是從左到右,從上到下。最后就是putImageData方法,把更改過(guò)的像素信息數(shù)組重新扔回畫(huà)布上。

一些小坑

第一個(gè)坑就是canvas用屬性去給寬高,別用css; 

第二個(gè)坑,做圖片處理好像得服務(wù)器環(huán)境,本地是不行的,聽(tīng)說(shuō)是基于什么安全考慮,最后我是通過(guò)搭本地服務(wù)器解決了canvas的報(bào)錯(cuò)。

第三個(gè)坑,棧溢出,這個(gè)目前還沒(méi)找到原因,后面會(huì)詳細(xì)講

變色的思路

主要思路來(lái)自于《啊哈!算法!》里面深度優(yōu)先搜索和廣度優(yōu)先搜索的章節(jié),該章節(jié)的最后一部分的“寶島探險(xiǎn)”實(shí)現(xiàn)了給不同的區(qū)域依次編號(hào),把編號(hào)看成染色,其實(shí)是一樣的。

具體實(shí)現(xiàn)

其實(shí)所謂的彩色二維碼,不是那種每個(gè)像素點(diǎn)顏色隨機(jī)的二維碼。仔細(xì)觀察二維碼就會(huì)發(fā)現(xiàn),黑色的部分是一塊一塊的,他們分布在白色當(dāng)中,就好像島嶼分布在海里,我們要做的就是把每個(gè)黑色塊單獨(dú)染色。黑色塊的實(shí)質(zhì)就是一個(gè)一個(gè)黑色的像素點(diǎn)。

前面也提到,我們使用canvas是因?yàn)榭梢赃M(jìn)行像素操作,所以我們的操作其實(shí)是給像素點(diǎn)染色,我們顯然不希望給背景色染色,所以背景色需要進(jìn)行一個(gè)判斷;前面也提到,背景色好像海洋分割了黑色的顏色塊,那也就是說(shuō)我們讀一個(gè)像素點(diǎn)進(jìn)行染色之后,不停的判斷它右側(cè)的像素點(diǎn)顏色,當(dāng)出現(xiàn)背景色的時(shí)候就說(shuō)明到達(dá)了邊界,可以停止右方向的染色,但是每個(gè)像素點(diǎn)其實(shí)有四個(gè)相連接的方向,當(dāng)一個(gè)像素點(diǎn)右邊就是背景色,我們應(yīng)該也去嘗試別的方向的可能性,這個(gè)就是深度優(yōu)先搜索,通過(guò)遞歸,不斷的驗(yàn)證當(dāng)前像素點(diǎn)的下一個(gè)位置的顏色,是背景色,那就回來(lái),嘗試別的方向;不是背景色,那就染色,然后對(duì)染色之后的這個(gè)像素點(diǎn)進(jìn)行四個(gè)方向的驗(yàn)證。

有幾點(diǎn)提一下,判斷是不是背景色,肯定得比對(duì)rgba的值,所以顏色參數(shù)得做處理,另一個(gè)就是像素點(diǎn)信息的數(shù)組,每四個(gè)元素代表一個(gè)像素,所以想要比對(duì)正確的像素信息,這部分也要處理。
可能說(shuō)的有點(diǎn)亂,我們看一下代碼

第一部分,canvas

// canvas 部分
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d");

var img = new Image();
img.src = path; //這里的path就是圖片的地址

第二部分,顏色的處理

// 分離顏色參數(shù) 返回一個(gè)數(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ù)

為了避免多余的操作,我們用一個(gè)標(biāo)記數(shù)組來(lái)記錄判斷過(guò)的位置

// 參數(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ù)組
// 隨機(jī)colors數(shù)組的一個(gè)序號(hào)
var ranNum = (function() {
 var len = colors.length;
 return function() {
  return Math.floor(Math.random() * len);
 }
})();

// 標(biāo)記數(shù)組 
var book = []; 
for (var i = 0; i < height; i++) { 
  book[i] = []; 
  for (var j = 0; j < width; j++) { 
    book[i][j] = 0; 
  } 
}

第四部分,獲取像素信息,對(duì)每個(gè)像素點(diǎn)進(jìn)行遍歷處理,最后扔回canvas

如果標(biāo)記過(guò),那就跳過(guò),如果沒(méi)標(biāo)記過(guò),那就隨機(jī)一個(gè)顏色,深度優(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)) { //沒(méi)標(biāo)記過(guò) 且是非背景色
    book[i][j] = 1;
    var color = colorRgb(colors[ranNum()]);
    dfs(i, j, color); //深度優(yōu)先搜索
   }
  }
 }

 ctx.putImageData(imgD, 0, 0);
}


// 驗(yàn)證該位置的像素 不是背景色為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];
}


// 返回對(duì)應(yīng)像素點(diǎn)的序號(hào)
function calc(width, i, j) {
 if (j < 0) {
  j = 0;
 }
 return 4 * (i * width + j);
}

關(guān)鍵代碼

我們通過(guò)一個(gè)方向數(shù)組,來(lái)簡(jiǎn)化一下操作,我們約定好,嘗試的方向?yàn)轫槙r(shí)針,從右邊開(kāi)始。

// 方向數(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++) {
  // 下一個(gè)坐標(biāo)
  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;
}

我遇到的最后一個(gè)坑就是當(dāng)長(zhǎng)寬大于220時(shí)就會(huì)棧溢出,但是小于這個(gè)值就不會(huì)有問(wèn)題,具體的原因還不清楚,猜測(cè)可能是判斷那里有問(wèn)題,導(dǎo)致死循環(huán)了。

全部代碼在這里

// 分離顏色參數(shù) 返回一個(gè)數(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;
  }
 }
})();

// 驗(yàn)證該位置的像素 不是背景色為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];
}


// 返回對(duì)應(yīng)像素點(diǎn)的序號(hào)
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++) {
  // 下一個(gè)坐標(biāo)
  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ù)組
// 隨機(jī)colors數(shù)組的一個(gè)序號(hào)
var ranNum = (function() {
 var len = colors.length;
 return function() {
  return Math.floor(Math.random() * len);
 }
})();

// 標(biāo)記數(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)) { //沒(méi)標(biāo)記過(guò) 且是非背景色
    book[i][j] = 1;
    var color = colorRgb(colors[ranNum()]);
    dfs(i, j, color); //深度優(yōu)先搜索
   }
  }
 }

 ctx.putImageData(imgD, 0, 0);
}

總結(jié)

雖然看起來(lái)有點(diǎn)長(zhǎng),其實(shí)大部分函數(shù)都在處理像素點(diǎn)的信息。實(shí)現(xiàn)起來(lái),主要就是得對(duì)深度優(yōu)先搜索有所了解,每個(gè)像素點(diǎn)都進(jìn)行深度優(yōu)先搜索,染過(guò)色的自然被標(biāo)記過(guò),所以當(dāng)一個(gè)新的沒(méi)標(biāo)記過(guò)的像素點(diǎn)出現(xiàn)時(shí),自然意味著新的顏色塊。細(xì)節(jié)方面,就是注意一下imgD.data和像素點(diǎn)序號(hào)之間的對(duì)應(yīng)關(guān)系,別的也就還好了。不過(guò)注意一點(diǎn)就是,因?yàn)橄袼攸c(diǎn)很小,所以肉眼覺(jué)得不相連的色塊也有可能是連在一起的,會(huì)染成一樣的顏色。

忘了放圖了,這里放幾張,拿qq截的,把外面的邊框不小心也截了,嘛,湊活看看吧

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JS實(shí)現(xiàn)骰子3D旋轉(zhuǎn)效果

    JS實(shí)現(xiàn)骰子3D旋轉(zhuǎn)效果

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)骰子3D旋轉(zhuǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • js實(shí)現(xiàn)列表循環(huán)滾動(dòng)

    js實(shí)現(xiàn)列表循環(huán)滾動(dòng)

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)列表循環(huán)滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 深入理解JavaScript事件機(jī)制

    深入理解JavaScript事件機(jī)制

    事件機(jī)制是幾乎所有開(kāi)發(fā)語(yǔ)言都有的機(jī)制,并不是deviceone的獨(dú)創(chuàng),在某些語(yǔ)言稱(chēng)之為消息(Event),有些地方稱(chēng)之為(Message).接下來(lái)通過(guò)本文給大家介紹JS事件機(jī)制的理解 ,需要的朋友一起學(xué)習(xí)吧
    2023-04-04
  • javascript sudoku 數(shù)獨(dú)智力游戲生成代碼

    javascript sudoku 數(shù)獨(dú)智力游戲生成代碼

    javascript sudoku 數(shù)獨(dú)智力游戲生成代碼,喜歡的朋友可以參考下。
    2010-03-03
  • js將控件隱藏的方法及display屬性介紹

    js將控件隱藏的方法及display屬性介紹

    這篇文章主要介紹了,js中將控件隱藏的方法,以及display的屬性,有需要的朋友可以參考一下
    2013-07-07
  • TypeScript 中接口詳解

    TypeScript 中接口詳解

    TypeScript核心設(shè)計(jì)原則之一就是類(lèi)型檢查,通過(guò)使用接口(Interfaces)可以進(jìn)行類(lèi)型檢查,滿(mǎn)足傳統(tǒng)面向?qū)ο笏枷?,利于有效開(kāi)發(fā),有效避免類(lèi)型轉(zhuǎn)換問(wèn)題。
    2015-06-06
  • JavaScript中if嵌套assert的方法詳解

    JavaScript中if嵌套assert的方法詳解

    在JavaScript中,通常我們不會(huì)直接使用`assert`這個(gè)詞,因?yàn)镴avaScript標(biāo)準(zhǔn)庫(kù)中并沒(méi)有直接提供`assert`函數(shù),下面是一個(gè)詳細(xì)的示例,展示如何在JavaScript中模擬`assert`函數(shù),并在`if`語(yǔ)句中嵌套使用它來(lái)檢查條件,需要的朋友可以參考下
    2024-09-09
  • HTML使用js給input標(biāo)簽增加disabled屬性的方法

    HTML使用js給input標(biāo)簽增加disabled屬性的方法

    最近項(xiàng)目上提出一個(gè)經(jīng)常遇到的需求,點(diǎn)擊新增時(shí)input可輸入,點(diǎn)擊編輯時(shí)input置灰,下面這篇文章主要給大家介紹了關(guān)于HTML使用js給input標(biāo)簽增加disabled屬性的相關(guān)資料,需要的朋友可以參考下
    2024-06-06
  • JavaScript 更嚴(yán)格的相等 [譯]

    JavaScript 更嚴(yán)格的相等 [譯]

    大部分JavaScript程序員都知道:應(yīng)該使用嚴(yán)格相等(===)來(lái)代替“普通”的相等操作(==).但是,有時(shí)候你的確需要一個(gè)比嚴(yán)格相等===更嚴(yán)格的運(yùn)算符,比如說(shuō):在你想檢查某個(gè)值是否是NaN的時(shí)候,又或者你想?yún)^(qū)分-0和+0的時(shí)候.本文解釋了相關(guān)的知識(shí)以及ECMAScript.next中的解決辦法:“is”操作符
    2012-09-09
  • 通過(guò)DOM腳本去設(shè)置樣式信息

    通過(guò)DOM腳本去設(shè)置樣式信息

    在大多數(shù)場(chǎng)合,我們都用CSS去設(shè)置樣式,但在某些特殊情況下,例如要根據(jù)元素在節(jié)點(diǎn)樹(shù)里的位置來(lái)設(shè)置節(jié)點(diǎn)樣式信息時(shí),目前CSS還沒(méi)辦法做到這一點(diǎn)。但利用DOM就可以很輕易的完成。
    2010-09-09

最新評(píng)論