一.要注意的问题
在chrome下会发生错误
Uncaught SecurityError:
Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
大概意思就是发生了跨域操作,也就是指图片的来源和当前的网页来源不同时,造成了跨域。
据说放到服务器上加载就会解决这个问题;我放到了本地的服务器环境可以顺利运行。以后凡是用到getImageData函数的地方,一定要使用此方法进行测试,此处不赘述。
二.知识点:
1.图片的加载:var img=new Image();
img.src = "timg.jpg";
img.οnlοad=function (){
context.drawImage( image , 0 , 0 );
}
2. getImageData() 从Canvas画板上取得所选区域的像素数据
①图片数据读取完成后,首先将图片数据绘制到Canvas画板上,用getImageData函数从画板上取得像素数据。
var imgData=context.getImageData(x,y,width,height);
x,y开始复制的起点坐标 width,height选择区域的长和宽
② ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
最后分析结果:data: 含有ImageData 对象所有的像素,每个像素都存在着四个值的信息,分别是r,g,b,a
这是一个简单像素处理:var pixelData = imageData.data;
for(var i=0;i<canvas.width*canvas.height;i++){
pixelData[4*i+0]=0;
pixelData[4*i+1]=0;
// pixelData[4*i+2]=0;
}
这是一个简单像素深浅处理:
var pixelData = imageData.data;
for(var i=0;i<canvas.width*canvas.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;//这个算法是图像学家研究出对RGB深浅的最好值
pixelData[i*4+0] = grey;
pixelData[i*4+1] = grey;
pixelData[i*4+2] = grey;
}
这是二维数组:遍历每一个像素
for( var i = 0 ; i < canvas.height ; i ++ )
for( var j = 0 ; j < canvas.width ; j ++ ){
//遍历第i行第j列的时候对应canvas的位移
var p = i*canvas.width + j;
//每一个点的像素值
pixelData[p*4+0] = r;
pixelData[p*4+1] =g;
pixelData[p*4+2] = b;
}
}
4.putImageData() 方法函数则表示将所得到的像素数据描画到Canvas画板上形成图形。
context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
其中imgdata为像素数据,dx、dy是绘制图片的定位坐标值,dirtyX、dirtyY是imgdata所要绘制图片的起始位置,dirtyXw、dirtyXh是imgdata所要绘制区域(相对imgdata的dirtyXx和dirtyXy坐标的偏移量)的宽度和高度值。这里面第4个参数以及其后的所有参数都可以省略,如果这些参数都省略了,则表示绘制整个imgdata。
5.getImageData函数从画板上取得像素数据。然后通过 putImageData() 将所取得的像素数据画到Canvas画板上var imgData=ctx.getImageData(10,10,50,50);
整个像素数据画到Canvas画板上:ctx.putImageData(imgData,10,70);
像素数据的一部分画到Canvas画板上:ctx.putImageData(imgData,200,260,50,50,100,100);
三.特效
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.clearfix:after,.zn-clearfix:before{content: ""; visibility: hidden; display: block; height: 0; clear: both; }
.clearfix{zoom:1;margin: 20px auto; width:1700px;}
</style>
</head>
<body>
<div class="clearfix">
<canvas id="canvasa" width="800" height="560" style="display:block;float:left;border:1px solid #aaa;"></canvas>
<canvas id="canvasb" width="800" height="560" style="display:block;float:right;border:1px solid #aaa;"></canvas>
</div>
<script>
var canvasa = document.getElementById("canvasa");
var contexta = canvasa.getContext("2d");
var canvasb = document.getElementById("canvasb");
var contextb = canvasb.getContext("2d");
var image = new Image();
window.onload = function(){
image.src = "1.jpg";
image.onload = function(){
contexta.drawImage( image , 0 , 0 , canvasa.width , canvasa.height );
}
}
</script>
</body>
</html>
灰度滤镜:
//灰度影响
function greyEffect(){
//通过 getImageData() 复制画布上指定矩形的像素数据,然后通过 putImageData() 将图像数据放回画布:
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;//这个算法是图像学家研究出对RGB深浅的最好值
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);
}
黑白滤镜:是指图像上只有白色,黑色;也就是rgb(255,255,255),或是rgb(0,0,0)。
//黑白滤镜:是指图像上只有白色,黑色;也就是rgb(255,255,255),或是rgb(0,0,0)。
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 );
}
反色滤镜:是指图像上的每一个点的RGB值修改为255-原来的值
//反色滤镜:是指图像上的每一个点的RGB值修改为255-原来的值
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 );
}
黑白,反色滤镜的每一个像素修改只需要参照自己当前的像素。
要注意:要保证周围的像素点不能被算法所修改,所以就不能仅仅使用一个imageData,需要创建一个imageData的拷贝var tmpImageData.
此后就参考tmpImageData,来修改imageData,最终把imageData结果传给putImageData,由此复制在画布上,同时当函数运行putImageData时,tmpImageData也就抛弃了。
模糊滤镜:模糊滤镜则需要参考自己周围的滤镜,图像上的每一个点的RGB值为周围的像素的平均值。
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;//来计算周围所有的RGB的总和
//一个像素点周围有8个像素点。
//二维循环编辑:基于中心点在x,y方向的位移的变化值,循环走了9次,
//下面这个就是点周围的点循环+自身(i,j)
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];
}
}
//遍历第i行第j列的时候对应canvas的位移
var p = i*canvasb.width + j;
//把周围的像素的平均值赋值(i,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 );
}