最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解使用JS如何制作簡(jiǎn)單的ASCII圖與單極圖

 更新時(shí)間:2017年03月31日 08:42:50   投稿:daisy  
這篇文章主要給大家介紹了使用JS如何制作簡(jiǎn)單的ASCII圖與單極圖的相關(guān)資料,文中介紹的非常詳細(xì),并在文末給出了詳細(xì)的示例代碼,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。

ASCII圖

在終端執(zhí)行各種命令的時(shí)候經(jīng)常會(huì)看到一些終端里顯示出來(lái)的"圖片",遠(yuǎn)看仿佛一張圖,近看則是一個(gè)個(gè)的 ASCII碼,它們 大致長(zhǎng)這樣子


而今天我們要做的則是用JS把一張給定的圖片轉(zhuǎn)換成這種用ASCII字符組成的“ASCII圖” 先看看最終效果,假設(shè)我們給定的圖片是這樣子的,


這是代碼處理后的結(jié)果,用了 I'mYasic 這8個(gè)字符來(lái)表示,還是可以分辨出大致的輪廓的。


單級(jí)圖

而另一種圖則是單極圖,也就是黑白圖片,還是剛剛那張圖片,輸出如下


基礎(chǔ)知識(shí)

這兩種圖都是比較簡(jiǎn)單的,只需要以下知識(shí)即可

  • HTML5中的Canvas
  • 像素的RGB值
  • JS中的Canvas相關(guān)API

制作ASCII圖

一般來(lái)說(shuō),在計(jì)算機(jī)當(dāng)中,我們看到的大多數(shù)圖片都是由一個(gè)個(gè)像素點(diǎn)構(gòu)成的,每一個(gè)像素點(diǎn)則由 RGBA 構(gòu)成,在 css 中我們時(shí)常用的 rgba(255, 255, 255, 255, 0)就是一組RGBA值, 也即是RGB三原色和Alpha透明度。當(dāng)然一張圖片不是僅僅包含所有像素點(diǎn)數(shù)據(jù)的,還包括一些描述信息,也稱為圖片的 profile,這一部分小則幾KB,多則幾百KB,是圖片壓縮中經(jīng)常被處理的部分。

那么對(duì)于圖片中每一個(gè)像素點(diǎn)來(lái)說(shuō),只要我們改變了其相應(yīng)的RGBA的值,最終的圖片也就變了樣子。而修改哪些像素點(diǎn)、修改成什么樣的RGBA,則決定著最終的圖片風(fēng)格,這也是許多濾鏡采用的機(jī)制。

基于以上的理論知識(shí),我們的ASCII圖制作思路也就有了。ASCII圖其實(shí)就是將一張圖中的一個(gè)像素點(diǎn),通過(guò)計(jì)算其RGBA的值,劃分成給定的幾個(gè)量化值,在這里由于我們用的 I'mYasic 這8個(gè)字符來(lái)表示,所以要分成8組值,每一組用一個(gè)ASCII字符來(lái)表示,最終就能組成一幅完整的ASCII圖片。

接下來(lái)就是具體的代碼實(shí)現(xiàn)。

獲取圖片的像素信息

通過(guò) Canvas API 中的 getImageData() 方法我們可以獲得一個(gè)對(duì)象,這個(gè)對(duì)象的屬性里包含一個(gè)一維數(shù)組 data,這個(gè)一維數(shù)組每4個(gè)元素為一組,代表了一個(gè) canvas 中指定范圍的全部像素信息,并且依次是 RED,GREEN,BLUE,ALPHA。因此我們可以先把圖片放進(jìn) canvas 中,再調(diào)用這個(gè)方法拿到像素。

不過(guò)我很疑惑為什么 data 是一個(gè)一維數(shù)組,通常處理的圖片都是二維圖片,如果用二維數(shù)組來(lái)表示像素信息,代碼讀取和處理會(huì)方便很多,也更容易理解。甚至可以用一個(gè)三維數(shù)組,專門(mén)用一個(gè)維度來(lái)放置RGBA信息。

獲取圖片像素信息的代碼如下所示

var canvasContext = canvas.getContext("2d");
canvasContext.drawImage(sourceImg, 0, 0);
var imgData = canvasContext.getImageData(0 , 0, sourceImg.width, sourceImg.height);
var imgDataArray = imgData.data;

那么對(duì)于某一個(gè)像素點(diǎn)的RGBA值就可以這樣獲取

var r = imgDataArray[lineIndex];
var g = imgDataArray[lineIndex + 1];
var b = imgDataArray[lineIndex + 2];
var a = imgDataArray[lineIndex + 3];

其中 lineIndex 是遍歷每一個(gè)像素點(diǎn)的基準(zhǔn)變量。

圖片灰度化

灰度化,也就是獲取像素點(diǎn)的灰度值。由于每一個(gè)像素點(diǎn)包含著RGBA四種信息,而我們需要將所有像素點(diǎn)的RGBA值分成8組,因此需要統(tǒng)一一下RGBA的值,最終得到一個(gè)值Y,而相應(yīng)的像素點(diǎn)的RGBA值滿足 Y = R = G = B ,在這里我們不考慮透明度 Alpha。由于RGB的值相等像素點(diǎn)顏色是介于白色與黑色之間的灰色,所以這一過(guò)程也稱為灰度化。

灰度化算法有很多種,我們?cè)谶@里采取最簡(jiǎn)單的方式,即

Y = (R + G + B) * 1/3

相應(yīng)代碼如下

function rgb2gray(r, g, b) {
 return r * 0.333 + g * 0.333 + b * 0.333;
}

灰度圖量化

灰度化以后的圖片大致長(zhǎng)這樣子,可以看到色彩已經(jīng)都變成灰色了。


那么接下來(lái)就是關(guān)鍵的“量化”過(guò)程。也就是說(shuō),我們要讓把這些不同灰度的值分成8組,并且每一組都賦予一個(gè)ASCII字符作為標(biāo)示,當(dāng)然選取的ASCII字符也要有一定規(guī)律,簡(jiǎn)單來(lái)說(shuō)就是顏色由深到淺相應(yīng)的字符由繁到簡(jiǎn)。而量化過(guò)程就是將0-255范圍等分成8個(gè)區(qū)間,依次判斷灰度值在哪一個(gè)區(qū)間內(nèi),代碼如下。

由于圖像像素?cái)?shù)目巨大,為了效率,判決時(shí)可以采取“二分判決”法提高判決速度。

function gray2asc(gray) {
 /*ASCII--I'mYasic*/
 /*32 64 96 128 160 192 224 256*/
 gray = 255 - gray;
 if (gray < 128){
  if (gray < 64){
   if (gray < 32){
    return '\''
   }
   else {
    return 'c'
   }
  }
  else {
   if (gray < 96){
    return 'i'
   }
   else {
    return 's'
   }
  }
 }
 else {
  if (gray < 192){
   if (gray < 160){
    return 'I'
   }
   else {
    return 'm'
   }
  }
  else {
   if (gray < 224){
    return 'a'
   }
   else {
    return 'Y'
   }
  }
 }
}

遍歷與顯示

上面大概講解完了對(duì)于一個(gè)像素點(diǎn)變換為ASCII碼的過(guò)程,接下來(lái)就是遍歷和顯示了。

遍歷

遍歷全部像素點(diǎn)并變換為ASCII碼基本是不可能的,因?yàn)閳D片稍微大一些計(jì)算量就增長(zhǎng)很多,所以我們折中一下,對(duì)于像素陣列的行與列都進(jìn)行等間隔采樣,最終展示出來(lái)的圖片分辨率會(huì)隨著采樣間隔減小而增強(qiáng)。另外要注意 data 數(shù)組是一維數(shù)組,并且每4個(gè)元素為一組RGBA數(shù)據(jù)。相應(yīng)代碼如下

 var result = "";
 var lineIndex = 0;
 for (var lineHeight = 0; lineHeight < sourceImg.height; lineHeight += 12){
  var lineASC = "";
  for (var lineFlag = 0; lineFlag < sourceImg.width; lineFlag += 5){
   lineIndex = (lineHeight * sourceImg.width + lineFlag) * 4;
   var r = imgDataArray[lineIndex];
   var g = imgDataArray[lineIndex + 1];
   var b = imgDataArray[lineIndex + 2];
   lineASC += gray2asc(rgb2gray(r, g, b));
  }
  lineASC += '\n';
  result += lineASC;
 }

顯示

最終獲得的 result 字符串就是需要展示的ASCII碼。但是必須注意,如果直接展示到頁(yè)面上會(huì)因?yàn)槊恳粋€(gè)字符的字符寬度不一樣而導(dǎo)致ASCII圖“失真”,這里我們可以采用 Monospace 字體來(lái)確保字符寬度一致。

制作單極圖

其實(shí)看完上面部分,就應(yīng)該知道單極圖非常好實(shí)現(xiàn),同樣需要獲取像素信息并灰度化,只是量化時(shí)直接量化為 rgb(0, 0, 0) 和 rgb(255, 255, 255) 兩種顏色就可以。

 var canvasContext = targetCanvas.getContext("2d");
 canvasContext.drawImage(sourceImg, 0, 0);
 var imgData = canvasContext.getImageData(0 , 0, sourceImg.width, sourceImg.height);
 var imgDataArray = imgData.data;
 for (var index = 0; index <= sourceImg.width * sourceImg.height * 4; index += 4){
  var red = imgDataArray[index];
  var green = imgDataArray[index + 1];
  var blue = imgDataArray[index + 2];
  var gray = rgb2gray(red, green, blue);
  if (gray < 128){
   imgData.data[index] = 0;
   imgData.data[index + 1] = 0;
   imgData.data[index + 2] = 0;
  }
  else {
   imgData.data[index] = 255;
   imgData.data[index + 1] = 255;
   imgData.data[index + 2] = 255;
  }
 }
 canvasContext.putImageData(imgData, 0, 0);

別忘了最后要用 putImageData 方法將修改后的像素信息放回 canvas 中進(jìn)行顯示。

ASCII圖完整代碼

function rgb2gray(r, g, b) {
 return r * 0.333 + g * 0.333 + b * 0.333;
}

function gray2asc(gray) {
 /*ASCII--I'mYasic*/
 /*32 64 96 128 160 192 224 256*/
 gray = 255 - gray;
 if (gray < 128){
  if (gray < 64){
   if (gray < 32){
    return '\''
   }
   else {
    return 'c'
   }
  }
  else {
   if (gray < 96){
    return 'i'
   }
   else {
    return 's'
   }
  }
 }
 else {
  if (gray < 192){
   if (gray < 160){
    return 'I'
   }
   else {
    return 'm'
   }
  }
  else {
   if (gray < 224){
    return 'a'
   }
   else {
    return 'Y'
   }
  }
 }
}

var img2ASC = function (canvas, sourceImg) {
 console.log(sourceImg.width + " " + sourceImg.height);

 var canvasContext = canvas.getContext("2d");
 canvasContext.drawImage(sourceImg, 0, 0);
 var imgData = canvasContext.getImageData(0 , 0, sourceImg.width, sourceImg.height);
 var imgDataArray = imgData.data;
 var result = "";
 var lineIndex = 0;
 for (var lineHeight = 0; lineHeight < sourceImg.height; lineHeight += 12){
  var lineASC = "";
  for (var lineFlag = 0; lineFlag < sourceImg.width; lineFlag += 5){
   lineIndex = (lineHeight * sourceImg.width + lineFlag) * 4;
   var r = imgDataArray[lineIndex];
   var g = imgDataArray[lineIndex + 1];
   var b = imgDataArray[lineIndex + 2];
   lineASC += gray2asc(rgb2gray(r, g, b));
  }
  lineASC += '\n';
  result += lineASC;
 }
 document.getElementById("result").innerHTML = result;
};

單極圖完整代碼

function rgb2gray(r, g, b) {
 return r * 0.333 + g * 0.333 + b * 0.333;
}

function gray2asc(gray) {
 /*ASCII--I'mYasic*/
 /*32 64 96 128 160 192 224 256*/
 if (gray < 128){
  if (gray < 64){
   if (gray < 32){
    return '\''
   }
   else {
    return 'c'
   }
  }
  else {
   if (gray < 96){
    return 'i'
   }
   else {
    return 's'
   }
  }
 }
 else {
  if (gray < 192){
   if (gray < 160){
    return 'I'
   }
   else {
    return 'm'
   }
  }
  else {
   if (gray < 224){
    return 'a'
   }
   else {
    return 'Y'
   }
  }
 }
}

var monoImg = function (targetCanvas, sourceImg) {
 targetCanvas.width = sourceImg.width;
 targetCanvas.height = sourceImg.height;
 var canvasContext = targetCanvas.getContext("2d");
 canvasContext.drawImage(sourceImg, 0, 0);
 var imgData = canvasContext.getImageData(0 , 0, sourceImg.width, sourceImg.height);
 var imgDataArray = imgData.data;
 for (var index = 0; index <= sourceImg.width * sourceImg.height * 4; index += 4){
  var red = imgDataArray[index];
  var green = imgDataArray[index + 1];
  var blue = imgDataArray[index + 2];
  var gray = rgb2gray(red, green, blue);
  if (gray < 128){
   imgData.data[index] = 0;
   imgData.data[index + 1] = 0;
   imgData.data[index + 2] = 0;
  }
  else {
   imgData.data[index] = 255;
   imgData.data[index + 1] = 255;
   imgData.data[index + 2] = 255;
  }
 }
 canvasContext.putImageData(imgData, 0, 0);
};

總結(jié)

這一篇博客主要講了利用JS中的 Canvas API 進(jìn)行一些簡(jiǎn)單的像素化操作,但其實(shí)還有很多地方可以繼續(xù)改進(jìn)。比如一般單極圖出來(lái)后很多地方會(huì)有噪點(diǎn),也就是一些礙眼的白點(diǎn)和黑點(diǎn),可以通過(guò)一些方式“去掉噪點(diǎn)”,就留在以后寫(xiě)吧!以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • 詳解ES7 Decorator 入門(mén)解析

    詳解ES7 Decorator 入門(mén)解析

    這篇文章主要介紹了詳解ES7 Decorator 入門(mén)解析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • 微信小程序(六):列表上拉加載下拉刷新示例

    微信小程序(六):列表上拉加載下拉刷新示例

    本篇文章主要介紹了微信小程序(六):列表上拉加載下拉刷新示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2017-01-01
  • 一篇文章詳解JS的四種異步解決方案

    一篇文章詳解JS的四種異步解決方案

    異步在JS中是常用的,下面這篇文章主要給大家介紹了關(guān)于JS四種異步解決方案的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用js具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-06-06
  • 一文熟練掌握J(rèn)avaScript的switch用法

    一文熟練掌握J(rèn)avaScript的switch用法

    在JavaScript中switch語(yǔ)句是一種用于多條件分支的控制語(yǔ)句,下面這篇文章主要給大家介紹了關(guān)于如果通過(guò)一文熟練掌握J(rèn)avaScript的switch用法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 一文搞懂JavaScript中原型與原型鏈

    一文搞懂JavaScript中原型與原型鏈

    js中的原型與原型鏈應(yīng)該是老生常談的話題了,在前端面試中基本都是必問(wèn)的一個(gè)問(wèn)題,但是很多人還是稀里糊涂的,只知道其表層含義。本文將帶大家深入了解JavaScript中的原型與原型鏈,感興趣的可以學(xué)習(xí)一下
    2022-10-10
  • Webpack 4如何動(dòng)態(tài)切割JS注入文件名詳解

    Webpack 4如何動(dòng)態(tài)切割JS注入文件名詳解

    這篇文章主要給大家介紹了關(guān)于Webpack 4如何動(dòng)態(tài)切割JS注入文件名的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Webpack4具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 用javascript實(shí)現(xiàn)自定義標(biāo)簽

    用javascript實(shí)現(xiàn)自定義標(biāo)簽

    用javascript實(shí)現(xiàn)自定義標(biāo)簽...
    2007-05-05
  • 淺析TypeScript中的類型檢查與錯(cuò)誤捕獲

    淺析TypeScript中的類型檢查與錯(cuò)誤捕獲

    類型檢查是一種靜態(tài)分析的過(guò)程,用于驗(yàn)證變量、函數(shù)和表達(dá)式的類型是否符合預(yù)期,這篇文章主要來(lái)和大家聊聊TypeScript中類型檢查與錯(cuò)誤捕獲的相關(guān)知識(shí),希望對(duì)大家有所幫助
    2023-06-06
  • js單例模式的兩種方案

    js單例模式的兩種方案

    這篇文章介紹了js單例模式的兩種方案,有需要的朋友可以參考一下
    2013-10-10
  • js實(shí)現(xiàn)移動(dòng)端輪播圖

    js實(shí)現(xiàn)移動(dòng)端輪播圖

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)移動(dòng)端輪播圖效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12

最新評(píng)論

通江县| 曲水县| 安义县| 丹凤县| 南郑县| 东兴市| 杭州市| 景谷| 浮梁县| 米林县| 建宁县| 竹北市| 卢氏县| 施甸县| 西乌珠穆沁旗| 城口县| 镶黄旗| 瑞昌市| 仙居县| 莱芜市| 天全县| 怀柔区| 田东县| 竹北市| 淅川县| 枣强县| 海淀区| 绥德县| 休宁县| 大连市| 田阳县| 抚顺县| 海原县| 田林县| 山丹县| 年辖:市辖区| 罗源县| 军事| 钦州市| 万盛区| 湟中县|