今天我們將認識如何操作Canvas的每個像素顏色。
drawImage方法讓我們可以將影像繪至Canvas畫布上。
首先介紹一個載入網址圖片的Promise函式drawImage
drawImage中,在圖片異步載入後使用Canvas方法drawImage方法將指定圖片畫至Canvas
接著回傳Canvas實例供我們操作,本篇內容將會使用到此函式。
function drawImage(imgURL) {
return new Promise(resolve => {
const img = new Image()
img.crossOrigin = 'anonymous'
img.addEventListener('load', e => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
// 將canvas尺寸設定與來源圖片一樣
const width = img.width
const height = img.height
canvas.width = width
canvas.height = height
// 繪圖
ctx.drawImage(img, 0, 0)
resolve(canvas)
})
img.src = imgURL
})
}
getImageData方法用以取得Canvas的ImageData實例
ImageData的屬性data
為畫布中像素的Buffer
通過修改這個Buffer,我們能夠實現真正的影像處理,意即實際操作每個像素的顏色。
通過修改畫布的ImageData之後,接著需要使用putImageData方法更新畫布
這個範例將會實現圖片Grayscale的效果
// 圖片來源: Google Image Search "apple"
const imgURL = 'http://juliandance.org/wp-content/uploads/2016/01/RedApple.jpg'
drawImage(imgURL).then(canvas => {
const width = canvas.width
const height = canvas.height
const ctx = canvas.getContext('2d')
const imageData = ctx.getImageData(0, 0, width, height)
console.log(imageData)
// [object ImageData] {
// data: [object Uint8ClampedArray],
// height: 456,
// width: 400
// }
const imageBuffer = imageData.data
console.log(imageBuffer) // [object Uint8ClampedArray]
let red, green, blue, alpha; // 定義各顏色的暫存變數
let arg
// 注意這裡的 i, 每次迭代時為 i += 4, 而非 i++
for (let i = 0; i < imageBuffer.length; i += 4) {
// 在imageBuffer之中每4個元素分別代表著每個像素的red, green, blue, alpha數值(0 ~ 255)
red = imageBuffer[i]
green = imageBuffer[i + 1]
blue = imageBuffer[i + 2]
alpha = imageBuffer[i + 3]
// 將畫布中每個像素的rgb值設定為rgb平均值,能使圖片灰階化
arg = (red + green + blue) / 3
imageBuffer[i] = arg
imageBuffer[i + 1] = arg
imageBuffer[i + 2] = arg
imageBuffer[i + 3] = alpha
}
ctx.putImageData(imageData, 0, 0)
document.body.appendChild(canvas)
})
請注意Demo中由於圖片來源並未設定允許跨域
因此Chrome瀏覽時必須搭配插件 cross-origin 才能正確看到結果。
本篇主題有幾個重點需特別注意
img.crossOrigin = 'anonymous'
, 否則無法用於drawImage
getImageData
取得Canvas的ImageData
實例,最後在處理完相術後要使用putImageData
更新Canvas