使用JavaScript进行基本图形操作与处理1.图像数据的相关接口由于HTML5引入了canvas标签,这大大简化了JavaScript处理图像的工作。通过canvas,JavaScript可以对图像进行像素级的操作,甚至还可以直接处理图像的二进制原始数据,这为图像的签名技术提供了支持。另外canvas还提供了常用的图像格式转换功能,可以使用JavaScript简单快捷地更改图像的编码方式。出于安全考虑,浏览器通常不允许处理跨域图像,但利用特殊的手段是可以突破这一限制的。解决处理跨域图像出现的安全警告的方法是使用CORS(Cross-OriginResourceSharing),具体可以参加。利用FileReader和canvas相配合,可以读取本地图像文件,比如我们有如下HTML代码:canvasid=myCanvas抱歉,您的浏览器还不支持canvas。/canvasinputtype=fileid=myFile/这两行HTML代码包含一个id为myCanvas的canvas画布,还包含一个id为myFile的文件选择控件,我们将通过文件选择控件为用户提供选择本地文件的接口,然后利用canvas画布为JavaScript提供图像处理的接口。下面通过JavaScript为这两个元素绑定事件。为了方便引用,先用两个变量来存储这两个元素:varmyCanvas=document.getElementById('myCanvas');varmyFile=document.getElementById('myFile');当用户选定一个文件时,我们就应开始通过FileReader读取文件数据,为此监视myFile的onchange事件,并构造FileReader:file.onchange=function(event){varselectedFile=event.target.files[0];varreader=newFileReader();reader.onload=putImage2Canvas;reader.readAsDataURL(selectedFile);}在这段代码中,onchange事件被激活时会传递一个event参数给处理函数,event的target子属性是一个描述当前文件选择控件的对象,其files属性是一个描述用户已选文件信息的数组。files是数组类型是因为HTML5支持一次选择多个文件,如果文件选择控件没有开启多选模式,那么此数组只有一个元素。接下来创建了一个FileReader对象,将其保存在reader中。reader.onload事件定义了文件加载完成后的操作,reader.readAsDataURL将文件内容读取成DataURL。接下来编写putImage2Canvas函数,这个函数用来将FileReader读取的数据放入canvas中供JavaScript处理:functionputImage2Canvas(event){varimg=newImage();img.src=event.target.result;img.onload=function(){myCanvas.width=img.width;myCanvas.height=img.height;varcontext=myCanvas.getContext('2d');context.drawImage(img,0,0);varimgdata=context.getImageData(0,0,img.width,img.height);//处理imgdata}}event是reader.onload传递的参数,event.target.result是FileReader读取的结果,由于之前我们将文件内容以DataURL的方式读取,所以可以直接将读取结果作为src创建图像对象。当图像创建完毕后,img.onload事件被激活,此时我们将canvas的尺寸设置成图像的尺寸,然后通过drawImage将图像画在画布上,最后通过getImageData获取图像像素数据供JavaScript处理。下面我们来详细了解下drawImage和getImageData这两个方法,这两个方法将会在后面的章节中一直用到,是JavaScript处理图像用到的最基本的方法。drawImage有三种用法,第一种是只指定图片的绘制位置:context.drawImage(img,x,y);这也是本节开始的代码实例中用到的使用方法,这种方法会将图片左上角置于坐标相对于画布的(x,y)点上,如果画布尺寸足够则画出整个图像,否则将超出画布的部分舍弃,如图1-1。图1-1超出画布部分的图像会被舍弃11图像来自Wikipedia,由Pamri上传。drawImage的第二种方法是指定指定图片绘制位置的同时图像的尺寸:context.drawImage(img,x,y,width,height);新绘制的图像会根据指定的尺寸进行放大或缩小,如图1-2。图1-2利用drawImage缩放图像drawImage的第三种用法是截取图片的一部分进行绘制:context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);sx和sy指定图像被截取部分左上角在图片上的坐标,swidth和sheight指定图像被截取部分的尺寸,x和y指定图像被截取部分画在画布上的位置,width和height指定图像被截取部分在画布上重绘的尺寸。图1-3中利用drawImage截取了图像的一部分并画在了画布上。图1-3利用drawImage截取图片的一部分getImageData方法用来获取canvas画布中图像的像素数据,使用方法比较简单,只需指定要获取图像左上角的位置和尺寸即可:context.getImageData(x,y,width,height);返回的数据是一个对象,此对象包含三个属性,分别是data、width和height,其中data就是图像的像素数据。data是一个一维数组,顺次记录着每个像素点的RGBA信息。R代表红色,G代表绿色,B代表蓝色,A代表不透明度,其取值范围均为0-255。对于A,0代表完全透明,255代表完全不透明。由于data是一个一维数组,所以在处理数据时应以每4个元素为单位读取data:for(vari=0,len=imgdata.data.length;ilen;i+=4){varr=imgdata.data[i],g=imgdata.data[i+1],b=imgdata.data[i+2],a=imgdata.data[i+3];//处理像素数据}比如最简单的反色操作,我们可以通过以下代码实现:for(vari=0,len=imgdata.data.length;ilen;i+=4){imgdata.data[i]=255-imgdata.data[i];imgdata.data[i+1]=255-imgdata.data[i+1];imgdata.data[i+2]=255-imgdata.data[i+2];}由于反色无需对图像的不透明度进行处理,所以我们只处理了R、G和B的数据。数据处理完毕后可以通过putImageData将处理结果输出到画布上:putImageData(imgdata,x,y);最后的处理结果如图1-4所示。图1-4通常操作图像像素数据反色处理图像toDataURL方法可以将canvas画布中的图像保存为图片:varimgsrc=myCanvas.toDataURL();varimg=document.create('img');img.src=imgsrc;toDataURL默认将图像转换为PNG图片,但也可以保存为JPEG图片:varimgsrc=myCanvas.toDataURL('image/jpeg');如果保存为JPEG图片,还可以通过第二个参数指定图片质量:varimgsrc=myCanvas.toDataURL('image/jpeg',quality);quality的取值范围为0.0-1.0,0.0代表图片质量最差,1.0代表图片质量最好。此外,Chrome浏览器还支持转换为WebP图像:varimgsrc=myCanvas.toDataURL('image/webp');2.图像几何变换得益于HTML5完善的图像处理接口,在对图像进行几何变换时,我们并不需要单独操作每个像素点,下面将对图像平移、图像缩放、镜像变换、图像旋转和图像转置的实现逐一讲解。2.1图像平移canvas通过translate方法实现图像平移。注意,translate平移的是canvas画布的坐标,并不会改变画布上已有图像的位置。translate的用法非常简单,只需指定canvas画布左上角平移后的坐标即可:context.translate(x,y);为进一步使读者理解,下面举一个例子。首先我们在画布的(10,10)处画出一幅图片:context.drawImage(img,10,10);然后将canvas画布左上角移至(100,100):context.translate(100,100);此时画布上的图像并没有变换,因为平移的是画布坐标,而不是画布上的图像,即图像并不与坐标一同平移。之后再次在画布的(10,10)处画出一幅图片:context.drawImage(img,10,10);以上代码执行完毕后的结果如图1-5所示。图1-5translate示例运行结果translate所操作的点永远都是画布的左上角,如果希望将执行context.translate(x,y)后画布的坐标恢复到之前的状态应再执行context.translate(-x,-y),画布默认的原点在左上角,水平方向右侧为正方向,垂直方向下侧为正方向,这与我们熟悉的直角坐标系有所不同。2.2图像缩放canvas通过scale对图像进行缩放。缩放后的画布的原点与原画布的原点相对应,所以如果希望以图像中心为参考点,缩放前应先将画布原点平移至图像中心。scale有两个参数,分别是画布横向的放大倍数和纵向的放大倍数:context.scale(scalewidth,scaleheight);比如context.scale(2,2)将画布的横向和纵向均变为原来的2倍,图1-6给出了缩放变换后的结果。[+]图1-6缩放变换后的结果缩放变换是对画布的变换,此操作并不影响已画在画布上的图像,比如如下代码不会改变图像:context.drawImage(img,10,10);content.scale(2,2);正确的方法是缩放图像前应先缩放画布,然后再开始绘图:content.scale(2,2);context.drawImage(img,10,10);scalewidth和scaleheight的绝对值大于1时为放大图像,小于1时为缩小图像,等于1是尺寸与原图像一致。如前所述,所以如果希望以图像中心为参考点,缩放前应先将画布原点平移至图像中心。比如下列代码以图像中心为参考点,将原图像缩小至原来的1/4(边长缩小至原来的1/2)://先将画布原点移至图像中心,此处图像中心也是画布的中心content.translate(myCanvas.width/2,myCanvas.height/2);//将画布缩小至原画布的1/4content.scale(0.5,0.5);//将原点还原content.translate(-myCanvas.width/2,-myCanvas.height/2);//将图像画在画布中context.drawImage(img,10,10);运行结果如图1-7所示。图1-7以图像中心为参考点缩放图像2.3镜像变换canvas中并没有为镜像变换专门提供方法,但不必紧张,至此我们依然尚未接触到像素级的操作。在上