HTML5提供了大量的方法来画图以及操作图像数据。直奔主题吧~
1.画图方法的3种不同的参数
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
image = new Image();
image.src = 'fence.png';
image.onload = function(e) {
context.drawImage(image, 0, 0);
};
这里最主要的是用到了drawImage(), 这个方法有3种不同的参数:
drawImage(image, dx, dy)
drawImage(image, dx, dy, dw, dh)
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
通过上图,我们对每个参数应该有了一定的了解了吧?
第一个方法主要作用是:将一张图画在画布的指定位置
第二个方法主要作用是:将一张图画以指定的宽和高画在画布的指定位置
第三个方法主要作用是:将一张图或它的一部分以指定的宽和高画在画布的指定位置。
这里要提醒大家的是,画布可以画图、画布、视频。
2.在画布区域外画画
我们在使用drawImage()时可以通过指定负数,调整图片的位置,从而在画布上显示我们所要的效果:
图中亮部就是画布的范围,而灰色部分则是超出画布区域的图片显示。通过这个原理,相信大家自然就会想到一种效果:放大镜。没错!我们还是先来看一下上面的效果是如何实现的吧:
function drawImage() {
var w = canvas.width,
h = canvas.height,
sw = w * scale,
sh = h * scale;
context.clearRect(0, 0, w, h);
context.drawImage(image, -sw/2 + w/2, -sh/2 + h/2, sw, sh);
}
3.在当前画布上显示另一个画布的内容
还是以上图为例,我们可以用如下方法:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image= new Image();
image.src='xxx.jpg';
context.drawImage(image,0,0);
context.drawImage(canvas,0,0,1000,1000)
我们仔细想想,其实这个方法还是有值得推敲的地方。为什么呢?因为浏览器等于每张图都要画两次,效率不是很高。在实际浏览器实际执行中,其实它会创建一个看不见的画布来放大图片。然后再重新放到当前画布。不过在图片缩放的应用中,我们还是可以使用的。
大家注意,此时我们引出了一个新的概念叫:Offscreen Canvases (屏幕外画布)
3.Offscreen Canvases (屏幕外画布)
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
offscreenCanvas = document.createElement('canvas'),
offscreenContext = offscreenCanvas.getContext('2d'),
...
// 设置offscreenCanvas的参数
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
...
// 向offscreenCanvas画画
offscreenContext.drawImage(anImage, 0, 0);
...
// 在当前画布上画出offscreenCanvas的内容
context.drawImage(offscreenCanvas, 0, 0,
offscreenCanvas.width, offscreenCanvas.height);
关于offscreenCanvas 我们注意两点:
1.offscreenCanvas默认大小是300px*150px 和普通画布的默认大小一样
2.这是一种思路,我们可以通两个画布间的交互,从而减少工序。应该好好推敲和使用。
4.ImageData对象操作
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.fillStyle = "red";
context.fillRect(10, 10, 50, 50);
function copy() {
var imgData = context.getImageData(10, 10, 50, 50);
context.putImageData(imgData, 10, 70);
}
</script>
<button onclick="copy()">Copy</button>
</body>
</html>
以上我们用到了两个主要的方法:
getImageData(in double sx, in double sy, in double sw, in double sh)返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
x 开始复制的左上角位置的 x 坐标。
y 开始复制的左上角位置的 y 坐标。
width 将要复制的矩形区域的宽度。
height 将要复制的矩形区域的高度。
我们在进一步深入下去之前,我们先来看看一些你必须知道的事~
对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
R - 红色 (0-255)
G - 绿色 (0-255)
B - 蓝色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
color/alpha 以数组形式存在,并存储于 ImageData 对象的 data 属性中。
如何遍历所有像素的RGBA呢?
for (var i=0;i<imgData.data.length;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];
imgData.data[i+3]=255;
}
这个方法在遍历像素的基础上,做了一个颜色反转的效果:
red=255-old_red;
green=255-old_green;
blue=255-old_blue;
大家可以到网上搜相关的滤镜教程来丰富自己的画布,滤镜运用的就是上述的原理,感兴趣的朋友可以分享自己的滤镜代码哟~
相信我们已经掌握了ImageDate的一些实质性的东西了,既然我们拿到了数据,就一定会有放回数据的命令,没错:
putImageData(in ImageData imagedata, in double dx, in double dy, in optional double dirtyX, in double dirtyY, in double dirtyWidth, in double dirtyHeight);将图像数据(从指定的 ImageData 对象)放回画布上。
imgData 规定要放回画布的 ImageData 对象。
dx ImageData 对象左上角的 x 坐标,以像素计。
dy ImageData 对象左上角的 y 坐标,以像素计。
dirtyX 可选。水平值(x),以像素计,在画布上放置图像的位置。
dirtyY 可选。水平值(y),以像素计,在画布上放置图像的位置。
dirtyWidth 可选。在画布上绘制图像所使用的宽度。
dirtyHeight 可选。在画布上绘制图像所使用的高度。
这里要提醒大家一下。有的时候,比如放大镜程序,有些朋友会频繁地调用getImageData()获取图像,这在手机上或者平板上会很大影响交互。比较好的解决办法是,只调用一次getImageData(),然后通过putImageData()将相关的矩形拷贝到画布上。
5.剪切选区
clip() 方法从原始画布中剪切任意形状和尺寸。
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.rect(50,20,200,120);
context.stroke();
context.clip();
context.fillStyle="green";
context.fillRect(0,0,150,100);
关于clip() 我们一般会配合 save()、restore()来使用。因为一旦我们clip()之后,你再进行clip()的话是基于上一个选区,换言之你的选区会越来越小。除非你要的是这种效果,否则我们可以这么来操作:
……
context.save();
//do somethong
context.clip();
restore()
//do something;
context.clip();
…….