关于getImageData
ctx.getImageData(),可以获取canvas的data图片数据,这个图片数据返回的data是一个对象,该对象包含指定的 ImageData 对象的图像数据。 对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
R - 红色 (0-255)
G - 绿色 (0-255)
B - 蓝色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
color/alpha 以数组形式存在,并存储于 ImageData 对象的 data 属性中。
ImageData.datalength 可以作这样计算:300(width) X 150(height) X 4(r,g,b,a 4个分量) = 180000
关于getImageData,我之前文章也有写过 https://www.haorooms.com/post/canvas_imageData 里面有利用getImageData,过滤视频纯色背景,吸取视频颜色,防锯齿,图片灰色及反色,图片下载等
今天在这个基础上再补充一些,主要是封装成函数,更方便调用,之前主要是demo案例,大家可以看看这些demo案例https://www.haorooms.com/post/canvas_imageData
canvas 应用补充
之前文章有写过,今天补充一下。
两个canvas画布
var canvasa = document.getElementById("canvasa")
var contexta = canvasa.getContext("2d")
var canvasb = document.getElementById("canvasb")
var contextb = canvasb.getContext("2d")
灰色效果
function greyEffect(){
var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var pixelData = imageData.data
for( var i = 0 ; i < canvasb.width * canvasb.height ; i ++ ){
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
var grey = r*0.3+g*0.59+b*0.11
pixelData[i*4+0] = grey
pixelData[i*4+1] = grey
pixelData[i*4+2] = grey
}
contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width , canvasb.height )
}
黑白效果
function blackEffect(){
var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var pixelData = imageData.data
for( var i = 0 ; i < canvasb.width * canvasb.height ; i ++ ){
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
var grey = r*0.3+g*0.59+b*0.11
if(grey > 125){
pv = 255
}
else{
pv = 0
}
pixelData[i*4+0] = pv
pixelData[i*4+1] = pv
pixelData[i*4+2] = pv
}
contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasa.width , canvasa.height )
}
反色
function reverseEffect(){
var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var pixelData = imageData.data
for( var i = 0 ; i < canvasb.width * canvasb.height ; i ++ ){
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
pixelData[i*4+0] = 255 - r
pixelData[i*4+1] = 255 - g
pixelData[i*4+2] = 255 - b
}
contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width , canvasb.height )
}
模糊
function blurEffect(){
var tmpImageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var tmpPixelData = tmpImageData.data
var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var pixelData = imageData.data
var blurR = 3
var totalnum = (2*blurR + 1)*(2*blurR + 1)
for( var i = blurR ; i < canvasb.height - blurR ; i ++ )
for( var j = blurR ; j < canvasb.width - blurR ; j ++ ){
var totalr = 0 , totalg = 0 , totalb = 0
for( var dx = -blurR ; dx <= blurR ; dx ++ )
for( var dy = -blurR ; dy <= blurR ; dy ++ ){
var x = i + dx
var y = j + dy
var p = x*canvasb.width + y
totalr += tmpPixelData[p*4+0]
totalg += tmpPixelData[p*4+1]
totalb += tmpPixelData[p*4+2]
}
var p = i*canvasb.width + j
pixelData[p*4+0] = totalr / totalnum
pixelData[p*4+1] = totalg / totalnum
pixelData[p*4+2] = totalb / totalnum
}
contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width , canvasb.height )
}
马赛克
function mosaicEffect(){
var tmpImageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var tmpPixelData = tmpImageData.data
var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height )
var pixelData = imageData.data
var size = 16
var totalnum = size*size
for( var i = 0 ; i < canvasb.height ; i += size )
for( var j = 0 ; j < canvasb.width ; j += size ){
var totalr = 0 , totalg = 0 , totalb = 0
for( var dx = 0 ; dx < size ; dx ++ )
for( var dy = 0 ; dy < size ; dy ++ ){
var x = i + dx
var y = j + dy
var p = x*canvasb.width + y
totalr += tmpPixelData[p*4+0]
totalg += tmpPixelData[p*4+1]
totalb += tmpPixelData[p*4+2]
}
var p = i*canvasb.width+j
var resr = totalr / totalnum
var resg = totalg / totalnum
var resb = totalb / totalnum
for( var dx = 0 ; dx < size ; dx ++ )
for( var dy = 0 ; dy < size ; dy ++ ){
var x = i + dx
var y = j + dy
var p = x*canvasb.width + y
pixelData[p*4+0] = resr
pixelData[p*4+1] = resg
pixelData[p*4+2] = resb
}
}
contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width, canvasb.height )
}
常用遍历方法:
let imgData = ctx.getImageData(0, 0, WIDTH, HEIGHT).data;
// 找到画布像素中的有色位置 index
// 第一行第一列 width * 4
// 第二行第二列
// ......
for(var y = 0; y < HEIGHT; y += skip) { // 遍历y轴方向的像素点
for(var x = 0; x < WIDTH; x += skip) { // 遍历x轴方向的像素点
idx = (x + y * WIDTH) * 4 - 1;
// y * width * 4 表示下一行(第几行)的意思
// x * 4 表示 index 相对的位置
// - 1 表示长度 - 1
// x*4 + y*width*4 -1
if(imgData[idx] > 0) {
// console.log('idx+++: ', idx)
// some code ......
} else{
// 表示小于0或等于0的情况
// some other code ......
// console.log('idx---: ', imgData[idx])
}
}
}
Canvas中对ImageData数据缩放
// imageData 要改版的数据,scale是缩放的尺寸,outCtx是输出的canvas ctx
function scaleImageData(imageData, scale, outCtx) {
var scaled = outCtx.createImageData(imageData.width * scale, imageData.height * scale)
for (var row = 0; row < imageData.height; row++) {
for (var col = 0; col < imageData.width; col++) {
var sourcePixel = [imageData.data[(row * imageData.width + col) * 4 + 0], imageData.data[(row * imageData.width + col) * 4 + 1], imageData.data[(row * imageData.width + col) * 4 + 2], imageData.data[(row * imageData.width + col) * 4 + 3]]
for (var y = 0; y < scale; y++) {
var destRow = Math.floor(row * scale) + y
for (var x = 0; x < scale; x++) {
var destCol = Math.floor(col * scale) + x
for (var i = 0; i < 4; i++) {
scaled.data[(destRow * scaled.width + destCol) * 4 + i] = sourcePixel[i]
}
}
}
}
}
return scaled
}
小结
温故而知新,之前的总结比较笼统,今天再次总结一下,比较使用的方法,可以直接项目中使用。比较方便。