canvas中getImageData改变大小及颜色

11059次浏览

关于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
  }

小结

温故而知新,之前的总结比较笼统,今天再次总结一下,比较使用的方法,可以直接项目中使用。比较方便。

Tags: canvasgetImageData

相关文章: