摘要:前言本文是接續(xù)系列教程的,主要是介紹顏色系統(tǒng)在中的應(yīng)用。本來是與一起成文的,因為莫名其妙的字?jǐn)?shù)限制只能分割放送了。提供可以獲取畫布上任何一個像素,并可以自由的操作他們。繪制指定的位置繪制對象的內(nèi)容。
前言
本文是接續(xù)系列教程的extra1,主要是介紹顏色系統(tǒng)在canvas中的應(yīng)用。
本來是與extra1一起成文的,因為segmentfault莫名其妙的字?jǐn)?shù)限制bug只能分割放送了。
你如果認(rèn)為canvas只是畫圖工具,那接下來的操作會顛覆你的認(rèn)知。canvas提供api可以獲取畫布上任何一個像素,并可以自由的操作他們。
獲取像素直接訪問像素的功能由canvas上下文中的ImageData對象提供,它提供了以下一組方法,都會返回ImageData對象。
getImageData()接受x軸坐標(biāo)、y軸坐標(biāo)、寬度、高度四個參數(shù),獲取畫布上這個矩形區(qū)域的像素數(shù)據(jù);
createImageData()可憑空創(chuàng)建指定寬高的矩形區(qū)域,初始是黑色,也可以輸入一個ImageData對象用于創(chuàng)建一個同樣大小的區(qū)域,但注意不會復(fù)制像素數(shù)據(jù)。
context.getImageData(x, y, width, height); context.createImageData(width, height); context.createImageData(anothorImageData);
獲取到的ImageData對象中data屬性是一個一維數(shù)組,乍看亂糟糟的,但細(xì)看你會發(fā)現(xiàn)其實這就是RGBA的顏色數(shù)據(jù),也就是數(shù)組中每個四位就是一個像素的顏色數(shù)據(jù),這里注意一下透明度A也是0~255,不是CSS里簡化過的0~1。
*
舉個例子
現(xiàn)在假定在一個純紅色區(qū)域取一塊2*2的矩形,我們得到的像素數(shù)據(jù)是:
let pixels = [255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255]
他們與圖像的對應(yīng)關(guān)系是從左到右,從上到下,大概就像上面代碼格式化這樣,如圖所示:
根據(jù)4對1的對應(yīng)關(guān)系,我們很容易就能寫出遍歷的辦法,offset就相當(dāng)于指針,每次移動4位,代碼如下:
for (let offset = 0, len = pixels.length; offset < len; offset += 4) { r = pixels[offset]; g = pixels[offset + 1]; b = pixels[offset + 2]; a = pixels[offset + 3]; }
當(dāng)需要訪問特定坐標(biāo)的像素時,可以使用如下公式,其中xpos是像素點在該區(qū)域的x坐標(biāo);ypos是像素點在該區(qū)域的y坐標(biāo),imagedata.width是指區(qū)域橫向有多少像素。
let offset = (xpos + ypos * imagedata.width) * 4; let r = pixels[offset]; let g = pixels[offset + 1]; let b = pixels[offset + 2]; let a = pixels[offset + 3];繪制像素
可以將修改過的ImageData對象重新用上下文的putImageData()方法繪制到指定區(qū)域,該方法接受三個參數(shù):ImageData對象、x軸坐標(biāo)、y軸坐標(biāo)。繪制指定的位置繪制ImageData對象的內(nèi)容。直接看下面例子的核心代碼。
先繪制鋪滿畫布的色塊,點擊按鈕觸發(fā)change事件處理器可改變顏色,過程見注釋。
完整例子:演示反色變化
【PS】對js了解不深的朋友可能會有疑問,遍歷過程操作的是pixels,imageData怎么會改變呢?
這是因為js中對象都是地址傳遞的特點,也就是pixels = imageData.data操作只是將pixels變量的指向到imageData.data所指向的內(nèi)存空間,所以操作pixels就是操作imageData.data。
window.onload = function () { const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // 繪制色塊,每個色塊寬10像素,高等于畫布高,鋪滿畫布 for (let i = 0; i < canvas.width; i += 10) { context.fillStyle = (i % 20 === 0) ? "#f00" : ((i % 30 === 0) ? "#0f0" : "#00f"); context.fillRect(i, 0, 10, canvas.height); } }; function change() { const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // 獲取整個畫布的ImageData對象 const imageData = context.getImageData(0, 0, canvas.width, canvas.height); // 取出顏色數(shù)據(jù) const pixels = imageData.data; // 遍歷顏色數(shù)據(jù)求每個顏色的反色 for (let offset = 0, len = pixels.length; offset < len; offset += 4) { pixels[offset] = 255 - pixels[offset]; pixels[offset + 1] = 255 - pixels[offset + 1]; pixels[offset + 2] = 255 - pixels[offset + 2]; // 這里沒有操作透明度 } // 將ImageData重新繪制到畫布上 context.putImageData(imageData, 0, 0); }更多有趣的例子
canvas強大的像素操作可以給我們帶來更多的可能,也許你會想開始做一個網(wǎng)頁版的美圖工具了吧(笑)。
這里還有一些有趣的demo可以玩玩:
演示灰度變化
有趣的色彩波紋
綜合案例有關(guān)顏色的番外部分到這里就基本完結(jié)了,最后有個綜合題,會應(yīng)用這些技術(shù)。
將系列第二篇中的鼠標(biāo)畫圖工具改造成鼠標(biāo)噴漆工具,這里建議自己動手實踐一下。
下面例子基本思路就是取得畫布像素數(shù)據(jù),每當(dāng)鼠標(biāo)點下并移動(執(zhí)行onMouseMove)就隨機改變鼠標(biāo)周圍一定范圍的像素點的顏色。
完整案例:鼠標(biāo)噴漆工具
window.onload = function () { const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // 獲得整個畫布區(qū)域的ImageData對象 const imageData = context.getImageData(0, 0, canvas.width, canvas.height); // 取出像素數(shù)據(jù) const pixels = imageData.data; // 設(shè)定筆刷大小 const brush_size = 25; // 設(shè)定筆刷密度 const brush_density = 80; // 筆刷的顏色變量 let brush_color; function onMouseMove() { // 根據(jù)設(shè)定的筆刷密度生成隨機像素點 for (let i = 0; i < brush_density; i++) { // 隨機像素點角度相對于鼠標(biāo)的角度 const angle = Math.random() * Math.PI * 2; // 根據(jù)設(shè)定的筆刷大小,隨機像素點以鼠標(biāo)為圓心的半徑 const radius = Math.random() * brush_size; // 計算出像素點的x軸相對坐標(biāo) const xpos = (mouse.x + Math.cos(angle) * radius) | 0; // 計算出像素點的y軸相對坐標(biāo) const ypos = (mouse.y + Math.sin(angle) * radius) | 0; // 算出該像素點在pixels中的偏移量 const offset = (xpos + ypos * imageData.width) * 4; // 對這個像素點的顏色數(shù)據(jù)進行操作,將顏色分解成三基色 pixels[offset] = brush_color >> 16 & 0xff; pixels[offset + 1] = brush_color >> 8 & 0xff; pixels[offset + 2] = brush_color & 0xff; pixels[offset + 3] = 255; } // 重新繪制區(qū)域 context.putImageData(imageData, 0, 0); } canvas.addEventListener("mousedown", () => { // 隨機一個顏色 brush_color = utils.parseColor(Math.random() * 0xffffff, true); canvas.addEventListener("mousemove", onMouseMove, false); }, false); canvas.addEventListener("mouseup", () => { canvas.removeEventListener("mousemove", onMouseMove, false); }, false); };
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93697.html
摘要:前言本文是接續(xù)系列教程的,主要是介紹顏色系統(tǒng)在中的應(yīng)用。本來是與一起成文的,因為莫名其妙的字?jǐn)?shù)限制只能分割放送了。提供可以獲取畫布上任何一個像素,并可以自由的操作他們。繪制指定的位置繪制對象的內(nèi)容。 前言 本文是接續(xù)系列教程的extra1,主要是介紹顏色系統(tǒng)在canvas中的應(yīng)用。 本來是與extra1一起成文的,因為segmentfault莫名其妙的字?jǐn)?shù)限制bug只能分割放送了。 ...
摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標(biāo)準(zhǔn)的?;跁r間的動畫其實無論是還是定時器,都不能保證以特定速率播放。將物體每幀移動距離,轉(zhuǎn)變?yōu)槲矬w每秒移動距離。 前言 本文雖說是基礎(chǔ)教程,但這是相對動畫/游戲領(lǐng)域來說,在前端領(lǐng)域算是中級教程了,不適合前端小白或萌新。閱讀前請確保自己對前端三大件(JavaScript+CSS+HTML)的基礎(chǔ)已經(jīng)十分熟悉,而且有高中水平的數(shù)學(xué)和物理知識。d...
摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標(biāo)準(zhǔn)的?;跁r間的動畫其實無論是還是定時器,都不能保證以特定速率播放。將物體每幀移動距離,轉(zhuǎn)變?yōu)槲矬w每秒移動距離。 前言 本文雖說是基礎(chǔ)教程,但這是相對動畫/游戲領(lǐng)域來說,在前端領(lǐng)域算是中級教程了,不適合前端小白或萌新。閱讀前請確保自己對前端三大件(JavaScript+CSS+HTML)的基礎(chǔ)已經(jīng)十分熟悉,而且有高中水平的數(shù)學(xué)和物理知識。d...
閱讀 2996·2023-04-26 00:23
閱讀 3407·2021-09-13 10:28
閱讀 2192·2021-08-31 14:18
閱讀 2895·2019-08-30 15:54
閱讀 1951·2019-08-30 15:43
閱讀 1286·2019-08-29 16:56
閱讀 2810·2019-08-29 14:16
閱讀 2063·2019-08-28 17:51