ctx.beginPath()ctx.translate(0, 0)ctx.fillStyle = "aqua"ctx.rect(0, 0, 100, 100)ctx.fill()ctx.closePath()五、图像处理
1.图片变换
1.1 状态的保存和恢复
由于canvas只是一个元素,并且只有一个上下文对象,不像div一样每个dom都可以单独设置css属性,当我们给上下文设置过颜色时,绘制下一个图形时使用的还是这个上下文对象,这样就给我们带来了不便
使用如下两个函数,可以将上下文对象在合适的地方进行保存,以及回退,从而达到每个元素的样式隔离
- save():用来保存最近一次的Canvas上下文的状态和属性。
- restore():用来获取save保存的Canvas之前的状态和属性。防止save后对Canvas执行的平移、放缩、旋转、错切、裁剪等可以改变画布的操作对后续的绘制的影响。
我们可以把save看成是一个入栈的过程,save一次,就向栈里面push一次cnavas的状态,而restore就是一个出栈的过程,每restore一次,就相当于弹出一次之前save的canvas状态,当前的canvas状态也就恢复成出栈的那个canvas状态,后面的图形的绘制就会在这个canvas状态之上绘制

TIP
save()和restore()必须成对使用,不然当使用requestAnimationFrame()时会造成页面卡顿
1.2 translate()
translate(x,y)方法用于平移图像。它接受两个参数,分别是 x 轴和 y 轴移动的距离(单位像素)。
js
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, 100, 100);
ctx.translate(50, 50);
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 100, 100);TIP
translate()方法必须在绘制路径方法之前使用。
1.3 rotate()
rotate(deg)方法用于图像旋转。它接受一个弧度值作为参数,表示顺时针旋转的度数。
js
ctx.rotate(radian)参数:
- radian:旋转的弧度,
(π/180) radian= 1 deg
TIP
rotate()方法必须在绘制路径方法之前使用。
旋转中心点始终是画布左上角的原点。如果要更改中心点,需要使用translate()方法移动画布。
1.4 scale()
scale(x,y)方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。默认值为 1
js
ctx.scale(scaleX, scaleY)参数:
- scaleX:水平缩放
- scaleY:垂直缩放
TIP
scale()方法必须在绘制路径方法之前使用。
缩放的是整个ctx对象,也就是整个canvas画布,需要根据需求使用translate()改变位置
1.5 transform()
transform()方法接受一个变换矩阵的六个元素作为参数,完成缩放、旋转、移动和倾斜等变形
js
ctx.transform(
scaleX,
skewX,
skewY,
scaleY,
translateX,
translateY
);参数:
- scaleX:水平缩放(默认值1,单位倍数)
- skewX:水平倾斜(默认值0,单位弧度)
- skewY:垂直倾斜(默认值0,单位弧度)
- scaleY:垂直缩放(默认值1,单位倍数)
- translateX:水平位移(默认值0,单位像素)
- translateY:垂直位移(默认值0,单位像素)
1.6 setTransform()
setTransform()方法取消前面的图形变换,将画布恢复到该方法指定的状态。该方法的参数与transform()方法完全一致。
js
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.translate(50, 50);
ctx.fillRect(0, 0, 100, 100);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.fillRect(0, 0, 100, 100);上面代码中,第一个fillRect()方法绘制的矩形,左上角从(0, 0)平移到(50, 50)。setTransform()方法取消了这个变换(已绘制的图形不受影响),将画布恢复到默认状态(变换矩形1, 0, 0, 1, 0, 0),所以第二个矩形的左上角回到(0, 0)。
2.图像合成
globalCompositeOperation 是 HTML5 Canvas 中的一个重要属性,它定义了源图像(绘制的新形状)与目标图像(现有的图像)之间的合成规则。不同的合成规则可以产生多种效果
在Canvas中globalCompositeOperation属性的值总共有26种类型,如下所示
目标图像
源图像
source-over:新的图像将覆盖在旧图像上。
3.绘制图片
Canvas API 允许将图像文件写入画布,做法是读取图片后,使用drawImage()方法将这张图片放上画布。
drawImage()有三种固定传参的方式,分别代表
- 三个参数:将图片的原始尺寸放在画布的指定位置
- 五个参数:将图片按照指定尺寸放在画布的指定位置
- 九个参数:在图片上截取区域,并按照指定大小放在画布指定位置
js
var img = new Image();
img.src = 'image.png';
ctx.drawImage(img, dx, dy);
ctx.drawImage(img, dx, dy, dWidth, dHeight);
ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);各个参数的含义如下。
| 参数 | 描述 |
|---|---|
| img | 图像元素 |
| sx | 开始裁剪的横坐标,注意此参数以图片原尺寸为标准 |
| sy | 开始裁剪的纵坐标,注意此参数以图片原尺寸为标准 |
| sWidth | 裁剪图像的宽度,注意此参数以图片原尺寸为标准 |
| sHeight | 裁剪图像的高度,注意此参数以图片原尺寸为标准 |
| dx | 图片相对于画布的横坐标 |
| dy | 图片相对于画布的纵坐标 |
| dWidth | 图像在画布内部呈现的宽度,会产生缩放效果。 |
| dHeight | 图像在画布内部呈现的高度,会产生缩放效果。 |
绘制图像分为以下三步:
- 实例化一个
Image对象 - 将图片的路径赋值给实例对象的
src属性 - 在实例对象的onload事件里使用
drawImage()方法
js
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
const img = new Image();
img.src ='img.png'
img.onload = function () {
ctx.drawImage(img, 0, 0,800,500);
};
}4.像素操作
对canvas画布中的像素进行操作,我们首先要了解ImageData对象
4.1 ImageData 对象
ImageData 实例对象中存储着 canvas 对象真实的像素数据,它包含以下几个只读属性:
- width:图片宽度,单位是像素
- height:图片高度,单位是像素
- data:Uint8ClampedArray 类型的一维数组,数组中每四个值分别代表R、G、B、A
- R - 红色 (0-255)
- G - 绿色 (0-255)
- B - 蓝色 (0-255)
- A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
通过构造函数创建ImageData对象
js
const img = new ImageData(array, width, height);
const img2 = new ImageData(width, height);参数:
- array:包含图像隐藏像素的
Uint8ClampedArray数组。如果数组没有给定,指定大小的黑色矩形图像将会被创建。 - width:无符号长整型(unsigned long)数值,描述图像的宽度。
- height:无符号长整型(unsigned long)数值,描述图像的高度。 如果已给定数组,这个值是可选的:它将通过它的大小和给定的宽度进行推断。
4.2 createImageData()
作用:创建一个新的,空白的ImageData 对象,有以下两种创建方法
1.按照宽高创建
js
var img = ctx.createImageData(width, height);2.按照已有的imageData对象创建
js
var img = ctx.createImageData(width, height);
var newImg = ctx.createImageData(img);4.3 getImageData()
作用:这个方法会返回一个 ImageData 对象,它代表了画布区域的对象数据
语法:
js
var imageData = ctx.getImageData(x, y, width, height);参数:
- x:需要提取的图像数据矩形区域的左上角横坐标
- y:需要提取的图像数据矩形区域的左上角数纵坐标
- width:需要提取的图像数据矩形区域的宽度
- height:需要提取的图像数据矩形区域的高度
4.4 putImageData()
作用:在场景中写入数据
语法:
- 三个参数:将像素数据原样绘制到画布中
- 七个参数:将像素数据中截取一部分绘制到画布中
js
ctx.putImageData(myImageData, dx, dy);
ctx.putImageData(myImageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);参数:
myImageData:ImageData对象
dx, dy:目标画布中的横纵偏移量
dirtyX,dirtyY:源图像中截取区域的左上角坐标
dirtyWidth,dirtyHeight:源图像中截取区域的宽高
5.区域检测
注意:以下两个方法不支持canvas自带的两个方法fillRect(),strokeRect()
使用以下方法代替
js
ctx.rect(x,y,w,h);
ctx.stroke(); //替代strokeRect();
ctx.rect(x,y,w,h);
ctx.fill(); //替代fillRect();5.1 isPointInPath()
isPointInPath(x,y)判断点(x,y)是否在路径被围成的区域内,返回布尔值
js
ctx.rect(100, 100, 100, 100);
ctx.stroke();
console.log(ctx.isPointInPath(150,150)) // truex:0y:0
是否在图形内:否
5.2 isPointInStroke()
isPointInPath(x,y)判断点(x,y)是否在路径的线上,返回布尔值
- 在区域内或在区域外都返回flase,只有在路径边框上才返回true
js
ctx.rect(100, 100, 100, 100);
ctx.stroke();
console.log(ctx.isPointInPath(100,100)) // truex:0y:0
是否在图形边缘上:否
6.裁剪路径
6.1 clip()
作用:将当前创建的路径设置裁剪的范围,对后面的图像进行裁剪
语法:
clip()有以下四个重载
js
clip()
clip(path)
clip(fillRule)
clip(path, fillRule)参数:
示例:
JS
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(canvas.width/2, canvas.height/2, 100, 0, Math.PI * 2);
ctx.stroke()
ctx.clip()
const img = new Image();
img.src = "./lufy.png";
img.onload = () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};以上代码以一个原型为裁剪范围,对后面的图像进行裁剪

7.保存图片
使用canvas.toDataURL() 方法可将canvas画布保存为图片
它返回一个包含被类型参数规定的图像表现格式的数据链接。返回的图片分辨率是 96dpi。
7.1 toDataUrl()
toDataUrl()是canvas对象上的一个方法,用于将canvas中的像素保存为图片
js
const canvas = document.querySelector("canvas");
// ...
canvas.toDataURL(type, encoderOptions);参数:
- type:图片的格式,一个字符串,可以为
'image/png' | 'image/jpeg' | 'image/webp',默认为image/png - encoderOptions:
- 在指定图片格式为
image/jpeg或image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。 - 值为一个0-1的数字,默认值为0.92,如果超出取值范围,将会使用默认值
0.92。其他参数会被忽略。
- 在指定图片格式为
下面是一个使用toDataUrl()保存图片的示例
js
// 绘制水印
const drawWatermark = (ctx) => {
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
ctx.save();
ctx.beginPath();
ctx.font = "15px Arial";
ctx.textAlign = "center";
ctx.rotate((-30 * Math.PI) / 180);
ctx.fillStyle = "gray";
ctx.fillText("水印文字", -100 + i * 100, 10 + j * 60);
ctx.closePath();
ctx.restore();
}
}
};
const drawRandomGraph=()=>{/*...*/} // 绘制随机图形
// 保存图片
const saveImage = () => {
const canvas = canvasRef.value;
const img = canvas.toDataURL("image/png", 1);
const a = document.createElement("a");
a.href = img;
a.download = "watermark.png";
a.click();
};7.2 toBlob()
toBlob()也是canvas对象上的方法,用于把canvas中的像素保存为Blob对象
js
canvas.toBlob(callback(blob), type, encoderOptions)参数:
- callback:转化后的回调
- blob:转化后的
Blob对象
- blob:转化后的
- type:图片的格式,一个字符串,可以为
'image/png' | 'image/jpeg' | 'image/webp',默认为image/png - encoderOptions:
- 在指定图片格式为
image/jpeg或image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。 - 值为一个0-1的数字,默认值为0.92,如果超出取值范围,将会使用默认值
0.92。其他参数会被忽略。
- 在指定图片格式为
上面保存图片的示例修改为toBlob()如下所示
js
const saveImage = () => {
const canvas = canvasRef.value;
canvas.toBlob((blob)=>{
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "watermark.png";
a.click();
},
"image/png",
1
);
};8.解决canvas模糊
js
function createHDCanvas(canvas, w, h) {
const ratio = window.devicePixelRatio || 1;
canvas.width = w * ratio; // 实际渲染像素
canvas.height = h * ratio; // 实际渲染像素
canvas.style.width = `${w}px`; // 控制显示大小
canvas.style.height = `${h}px`; // 控制显示大小
const ctx = canvas.getContext("2d");
ctx.scale(ratio, ratio);
// canvas 绘制
return canvas;
}
createHDCanvas(canvas, window.innerWidth, window.innerHeight);
window.onresize = () => {
createHDCanvas(canvas, window.innerWidth, window.innerHeight);
};