ImageData 是图片的数据化,它具备以下属性:
注:Uint8ClampedArray 翻译过来是 8位无符号整型固定数组,其取值范围是[0,255]。若小于0,则为0,大于255,则为255。若为小数,则取整,取整的方法是银行家舍入。
1.直接建立ImageData() 对象(相当于自己新建了一张图片)
new ImageData()
new ImageData(width, height)
new ImageData(Uint8ClampedArray, width, height)
ctx.createImageData()
ctx.createImageData(width, height)
ctx.createImageData(ImageData)2.获取canvas 的ImageData() 对象(可以以此原理获取真实图片的数据)
ctx.getImageData(x, y, width, height)putImageData(ImageData, dx, dy, x, y, w, h) 将 ImageData 对象显示在 canvas 画布之中

代码示例:
const canvas=document.getElementById('canvas');
//canvas充满窗口
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;
const ctx=canvas.getContext('2d');
const img=new Image();
img.src='./images/dog.jpg';
img.onload=function(){
//获取图片宽高
const {width,height}=img;
/*1.在canvas 中绘制图像*/
ctx.drawImage(img,0,0);
/*2.从canvas 中获取图像的ImageData*/
const imgData=ctx.getImageData(0,0,width,height);
/*3.在canvas 中显示ImageData*/
ctx.putImageData(
imgData,
//位置
0,height,
//裁剪
150,150,
100,100
)
};ImageData 对象的属性:

for(let i=0;i<data.length;i+=4){
let r=data[i+0];
let g=data[i+1];
let b=data[i+2];
let a=data[i+3];
console.log(r,g,b,a)
}for(let y=0;y<h;y++){
for(let x=0;x<w;x++){
let ind=(y*w+x)*4;
let r=data[ind];
let g=data[ind+1];
let b=data[ind+2];
let a=data[ind+3];
console.log(r,g,b,a)
}
}我们逐像素遍历ImageData 对象中的每个像素,然后将其置灰,效果如下:

像素置灰的算法是:
const lm =0.299*r + 0.587*g + 0.114*b我们可以逐行列遍历ImageData 对象里的像素,将特定区域的颜色变成色块,从而变成马赛克效果。

我们可以通过不同的算法,对 ImageData 中的像素进行不同的处理。比如调整图片的色调,检测图像边缘,实现艺术效果……

状态管理,管理的是上下文对象的状态。
上下文对象的状态就是上下文对象的属性。比如描边颜色,填充颜色,投影,线条样式,变换信息…
管理上下文状态的方法有两个:
一般在我们绘制具备同一种样式的图形时,都会用 save() restore() 将其包裹起来。这是为了避免当前的图形样式影响以后所要绘制的图形样式。
状态是可以嵌套的:
a - save()
b - save()
restore() – b
restore() – a代码示例:
ctx.save();
ctx.fillStyle='green';
ctx.fillRect(50,50,400,200);
ctx.restore();
ctx.save();
ctx.fillStyle='red';
ctx.fillRect(50,300,400,200);
ctx.restore();变换的本质是对 canvas 坐标系的操作
变换有3个特性:

代码示例:
ctx.fillStyle='green';
ctx.translate(100,100);
ctx.fillRect(100,100,400,200);
代码示例:
ctx.fillStyle='green';
ctx.rotate(Math.PI/24);
ctx.fillRect(100,100,400,200);
代码示例:
ctx.fillStyle='green';
ctx.scale(0.5,0.5);
ctx.fillRect(100,100,400,200);我们之前所说的 translate(x,y)、rotate(angle) 和 scale(x,y) 方法都是属于矩阵变换的。
除此之外canvas 还提供了两个完整的矩阵变换方法:

解释一下上面的参数:
关于矩阵变换的算法,我们这里先不做详解,其中涉及的知识量有点大,之后咱们会再单独拿出一篇文章来说矩阵。

当前案例会用到两种变换:
globalAlpha 就是全局对象的透明度,全局对象就是 canvas 的上下文对象。 使用方法:ctx.globalAlpha=0.6

代码示例:
ctx.save();
ctx.globalAlpha=0.5;
ctx.fillRect(50,50,400,200);
ctx.fillRect(150,150,400,200);
ctx.restore();
ctx.fillRect(250,250,400,200);注意:globalAlpha 要和颜色里的rgba 区别一下
rgba 控制的是某种颜色的透明度;
globalAlpha 相当于给之后绘制的所有图形统一设置透明度。
路径裁剪就是在画布上设置一个路径,让我们之后绘制的图像只显示在这个路径之中。
路径裁剪的步骤:
代码示例:
ctx.beginPath();
ctx.arc(300,300,100,0,Math.PI*2);
ctx.stroke();
ctx.clip();
ctx.fillRect(300,300,100,100);全局合成是 canvas 画布中的已绘图像和将绘图像的融合方式
我们可以从形状和色彩两方面解读全局合成
以下图为例,说一下全局合成的步骤

绿色的圆会基于全局合成属性与黄色的正方形合成
刮刮乐的绘制步骤:
1.用 css 在 canvas 中添加一个背景

2.在 canvas 中绘制一张遮罩图

3.在canvas 画布中实现手绘效果

4.将手绘效果与遮罩做destination-out 合成

已绘制到 canvas 上的图像不可被修改,只能被覆盖或擦除
路径裁剪是基于路径的一种合成方式,它只能使用路径设置裁剪区域,如果是文字的话,就无效
透明度合成和全局合成都是基于像素的操作