# canvas 对图片处理

# 1. 绘制,裁剪

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let img = document.querySelector('#img')
let canvas = document.querySelector('#canvas')
let ctx = canvas.getContext('2d')
img.onload=()=>{
canvas.width = img.width
canvas.height = img.height
//第一种绘制方法,第一个为图像的Dom,第二个参数为,图像绘制到画布的水平位置,第三个参数为,图像绘制到画布的竖直方向
ctx.drawImage(img,0,0)
//第二种绘制方法可以进行,前三个参数一样,width为图像在画布的宽度,如果这个值比canvas本身的宽度要大便是放大,要小就是缩小。height也一样。
ctx.drawImage(img,0,0,width,height)
//第三种绘制方法为裁剪。
sx: 裁剪点位于最左边的位置的差值
sy: 裁剪点位于最上边的位置的差值
swidth: 裁剪宽度
sheight 裁剪高度
这四个与裁剪相关用于确定裁剪位置以及裁剪宽高。
后面四个参数与第二种绘制方法的后面四个参数一致,前两个用来确定绘制点的位置,后面两个用来确定绘制的宽高。
ctx.drawImage(img,sx,sy,swidth,sheight,dx,dy,dwidth,dheight)
}

# 2. 变换

变换为坐标系的改变,如果想让 canvas 的图片发生改变需先改变坐标系,在绘制图片。

1
2
3
4
ctx.scale(x,y) //x为水平伸缩倍数,y为竖直伸缩倍数。
ctx.translate(x,y) //x为水平移动的距离,y为竖直移动的距离。
ctx.rotate(r) //r为旋转的角度,旋转的点为坐标系原点,默认在左上角,可以通过translate更改原点位置。
ctx.transform(a,b,c,d,e,f) //a:水平缩放,b:垂直倾斜,c:水平倾斜,d:垂直缩放,e:水平移动,f:垂直移动。其实这是一个三阶矩阵。二维图形要选择,缩放需要二阶矩阵,而平移是仿射变化所以需要增加一个维度记录方向。所以图形的缩放,选择,平移需要一个三阶矩阵实现,

# 3. 像素控制

如果直接在本地文件打开并使用 getImageData () 这个函数获取图片的数据的话,会出现跨域问题,可以使用 live serve 这个 vscode 插件,运行文件。关于跨域问题可以参考这个

# 1. 灰度图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ctx.drawImage(img,0,0,img.width,img,height) //先绘制图片,img为dom
let imageData = ctx.getImageData(0,0,img.width,img.height) //获取图片数据
//获取灰度图片,运用0.299*r+0.587*g+0.114*b这个公式获取某一个rgb下的灰度值,当rgb相同时就会呈现灰色。
for(let i=0;i<imageData.data.length;i+=4){ //每一个像素点有四个值分别是rgba,其中a是透明度。
let r = imageData.data[i]
let g = imageData.data[i+1]
let b = imageData.data[i+2]
let avg = .299 * r + .587 * g + .114 * b
imageData.data[i] = avg
imageData.data[i+1] = avg
imageData.data[i+2] = avg
}
//这个函数有两种写法,第一种
ctx.putImageData(imageData,x,y) //x为离坐标原点的水平距离,y为离坐标原点的垂直距离,坐标原点默认是左上角。可以使用translate更改。这个可以改变绘制后图像的改变的位置
第二种写法
ctx.putImageData(imageData,x,y,dx,dy,width,height)
前三个参数与第一种写法一致。后面的参数主要是选择要覆盖原图像的位置。
dx:新图像绘制在原图像的水平位置
dy:新图像绘制在原图像的竖直位置
width:新图像的宽度
height:新图像的高度
1
2

# 2. 各种滤镜的实现

  1. 反色:新 rgb 为(255-r,255-g,255-b)

  2. 灰色调:新 rgb 为

    r:(r * 0.272) + (g * 0.534) + (b * 0.131)

    g:(r * 0.349) + (g * 0.686) + (b * 0.168)

    b:(r * 0.393) + (g * 0.769) + (b * 0.189)

  3. 模糊:做卷积,具体原理可以看这个【官方双语】那么…… 什么是卷积?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
let img = document.querySelector('#img')
let canvas = document.querySelector('#canvas')
let invertColor = document.querySelector('#invertColor')
let adjustColor = document.querySelector('#adjustColor')
let blurImage = document.querySelector('#blurImage')
let fudiaoImage = document.querySelector('#fudiaoImage')
let kediaoImage = document.querySelector('#kediaoImage')
let mirrorImage = document.querySelector('#mirrorImage')
let ctx = canvas.getContext('2d')
let invertColorctx = invertColor.getContext('2d')
let adjustColorctx = adjustColor.getContext('2d')
let blurImagectx = blurImage.getContext('2d')
let fudiaoImagectx = fudiaoImage.getContext('2d')
let kediaoImagectx = kediaoImage.getContext('2d')
let mirrorImagectx = mirrorImage.getContext('2d')
img.src="./img/cover.jpg"
img.onload=()=>{
//图片灰度
canvas.width = img.width
canvas.height = img.height
ctx.drawImage(img,0,0,img.width,img.height)
let imageData = ctx.getImageData(0,0,img.width,img.height)
for(let i=0;i<imageData.data.length;i+=4){
let r = imageData.data[i]
let g = imageData.data[i+1]
let b = imageData.data[i+2]
let avg = .299 * r + .587 * g + .114 * b
imageData.data[i] = avg
imageData.data[i+1] = avg
imageData.data[i+2] = avg

}
ctx.putImageData(imageData,0,0,0,0,img.width,img.height)
//图片反色调
invertColor.width = img.width
invertColor.height = img.height
invertColorctx.drawImage(img,0,0,img.width,img.height)
let invertColorData = invertColorctx.getImageData(0,0,img.width,img.height)
for(let i=0;i<invertColorData.data.length;i+=4){
invertColorData.data[i] = 255-invertColorData.data[i]
invertColorData.data[i+1] = 255-invertColorData.data[i+1]
invertColorData.data[i+2] = 255-invertColorData.data[i+2]
}
invertColorctx.putImageData(invertColorData,0,0)
//图片灰色调
adjustColor.width = img.width
adjustColor.height = img.height
adjustColorctx.drawImage(img,0,0,img.width,img.height)
let adjustColorData = adjustColorctx.getImageData(0,0,img.width,img.height)
for(let i=0;i<adjustColorData.data.length;i+=4){
let r = adjustColorData.data[i]
let g = adjustColorData.data[i+1]
let b = adjustColorData.data[i+2]
adjustColorData.data[i] = (r * 0.272) + (g * 0.534) + (b * 0.131)
adjustColorData.data[i+1] = (r * 0.349) + (g * 0.686) + (b * 0.168)
adjustColorData.data[i+2] = (r * 0.393) + (g * 0.769) + (b * 0.189)
}
adjustColorctx.putImageData(adjustColorData,0,0)
//图片模糊,这里是用3X3的卷积核
blurImage.width = img.width
blurImage.height = img.height
blurImagectx.drawImage(img,0,0,img.width,img.height)
let blurImageData = blurImagectx.getImageData(0,0,img.width,img.height)
for(let i=0;i<blurImageData.height-2;i++){
for(let j=0;j<blurImageData.width*4-8;j+=4){
let list1 = [0,1,2],list2 = [0,4,8]
let tr=0,tg=0,tb=0
list1.forEach((a)=>{
list2.forEach((b)=>{
let num = j+b+(i+a)*blurImageData.width*4
tr += blurImageData.data[num]
tg += blurImageData.data[num+1]
tb += blurImageData.data[num+2]
})
})
tr = tr/9
tg = tg/9
tb = tb/9
list1.forEach((a)=>{
list2.forEach((b)=>{
let num = j+b+(i+a)*blurImageData.width*4
blurImageData.data[num] = tr
blurImageData.data[num+1] = tg
blurImageData.data[num+2] = tb
})
})
}
}
blurImagectx.putImageData(blurImageData,0,0)
}

最终效果,如下

相关资料

25 - 像素操作_哔哩哔哩_bilibili

纯 JavaScript 实现 HTML5 Canvas 六种特效滤镜・HTML5 Canvas 编程・看云 (kancloud.cn)