介绍

canvasH5中新加的一个标签

1
<canvas width='1200' height='800'> </canvas>

标签主要的属性如图,仅需widthheight两个

就俩? 看着很简单不是? 当然不是 ╮(╯▽╰)╭ , 因为canvas是一个需要和js结合使用的标签

1
2
3
4
5
6
7
8
9
<body>
<canvas width='1200' height='800' id='canvas'> </canvas>
</body>

<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d') // 2d ? 有3d咩 ? 有 => webgl :)
...
</script>

canvas拿的是画板, ctx拿的是画笔, 画图主要的是通过画笔不是, 所以我们使用的也基本上是ctx身上的属性和方法, ctx身上有许多画图的方法:

  • 画线的 lineTo(x, y)
  • 画矩形的 rect(x, y, width, height)
  • 画弧 / 圆的 arc(x, y, r, startAng, endAng, true/false)
  • 画文本的 fillText('Hello World!')
  • 画图片的 drawImage(imgData, x, y, width, height)

以上只是简写, 有许多细节并未说明, 想细学的可以去

w3cmdn

本文只介绍canvas对图片的相关操作,也就是围绕drawImage方法展开

Tips: 以下操作都在node服务器下操作, 文本域下会存在跨域问题, 无法实现一些操作

玩法一: 图片的组合

在工作中难免会遇到需要前端画图的场景,根据用户的选择,动态的生成海报之类的,这时候就需要使用我们的canvas了,先看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<canvas width='384' height='683' id='canvas'></canvas> // ? => 和图片大小相关
</body>

<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
咱继续 (*^▽^*)
const img1 = new Image()
img1.src = './qiu.png'
img1.onload = () => {
ctx.drawImage(img1, 0, 0, canvas.width, canvas.height)
}
</script>

ctx.drawImage(imgdata, x, y, width, height)方法的参数有5个,分别是:

  • x 绘制图像的左上点x轴坐标
  • y 绘制图像的左上点y轴坐标
  • width 绘制图像的宽度
  • height 绘制图像的高度
  • imgdata 这个在MDN的叫法为CanvasImageSource说人话是canvas图像源, 还听不懂?没关系我也不懂,总之常用的就是本文中的HTMLImageElementHTMLVideoElement

HTMLImageElementHTMLVideoElement又是啥? 哈哈,其实就是img标签video标签

1
2
3
4
5
6
7
8
const img1 = new Image() 
等于
const img1 = document.createElement('img')
也等于
<img id='img' src=''></img>
const img1 = document.getElementById('img')

<video>标签也可以哦

此时的界面

img

空荡荡的篮球显得很孤独 (ノへ ̄、) , 所以,我们得为他加个伴

1
2
3
4
5
6
7
8
9
10
11
12
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const img1 = new Image()
const img2 = new Image()
img1.src = './qiu.png'
img1.onload = () => {
ctx.drawImage(img1, 0, 0, canvas.width, canvas.height)
img2.src = './cai.png'
img2.onload = () => {
ctx.drawImage(img2, 40, 180, 315, 453)
}
}

看图

img

完美! (≧∀≦)ゞ

tips1: 注意要在img1加载完成后的回调函数中在给img2赋值src, 因为后绘制的会抹除先绘制的, 会出现f覆盖关系错误的问题

tips2: 这拙略的抠图, 辣眼睛 : (

以上就是canvas对图像进行组合的方法, so easy是不是!

玩法二 下载

图片组合好了, 该怎么保存(下载)呢?

首先我们得知道下载可分为两种:

  1. 本地下载
  2. 服务端下载

本地下载是指纯前端操作, 不经过后端接口直接保存, 而服务端下载则是通过接口返回的图片数据下载

本次只讲本地下载 , 服务端下载我会在下篇node文章中讲明

那本地下载咋下呢? 看下图你就知道了:

img

没错, 就是右键另存为 (>▽<)

啥? 你不听? 你不会右键?? 你要能看的见的下载???

img

好吧, 谁让我是个好人

先来个按钮

1
2
<canvas id='ctx' width="384" height="683"></canvas>
<p><button onclick='download()'>下载</button></p>

如图

img

1
2
3
4
5
6
7
base64_img = canvas.toDataURL()
const download = () => {
const a = document.createElement('a')
a.href = base64_img
a.download = 'download.jpg'
a.click()
}

canvas.toDataURL()方法是将画布(canvas)的信息转为base64格式

download方法则是模拟一个a标签点击, 此方法确实可以下载, 但有个小弊端就是下载后的图片会偏大(存储的大小), 这是由于转为base64格式所造成的

以上就是canvas图像的下载, 有些瑕疵, 但目前我也没找到别的好方法, 以后我会了会补全这篇文章的!

canvas像素操作 - 图片滤镜

换张图

1
2
3
4
5
6
7
8
9
10
11
<canvas id='ctx' width="1200" height="800"></canvas>
<p><button onclick='blackWhite()'>黑白滤镜</button></p>
<script>
const canvas = document.getElementById('ctx')
const ctx = canvas.getContext('2d')
const img = new Image()
img.src = './flowers.webp'
img.onload = () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
}
</script>

img

本来想多举几个例子, 但写到这里有点晕晕的, 这里就举一个黑白滤镜的例子把

继续

1
2
3
4
5
6
7
8
9
10
11
const blackWhite = () => {
let myData = ctx.getImageData(0, 0, canvas.width, canvas.height)
let arr = []
for(let i = 0; i < myData.data.length; i++) {
if ((i+1)%4 == 0) {
let total = (myData.data[i - 1] + myData.data[i - 2] + myData.data[i - 3]) / 3
myData.data[i - 1] = myData.data[i - 2] = myData.data[i - 3] = total
}
}
ctx.putImageData(myData, 0, 0)
}

ctx.getImageData(0, 0, canvas.width, canvas.height)

是拿到该画布上的所有像素点, 返回的格式是一个巨大的数组:

1
[255, 255, 0, 255, ...]

四位为一个像素点, 分别对应R = 255, G = 255, B == 0, A == 255, 也就是说改点是一个透明度为1的纯黄色像素点,知道了这个后, 想弄成黑白滤镜就有了方向

我们还得知道一个小知识, 那就是, 当R,G,B值相同时会显示为灰色, 且数值越大越亮, 如255, 255, 255 为白色

所以我们可以将每项的元素点的R,G,B加起来除以三赋值给他们, 就实现了黑白滤镜, 如下

1
2
let total = (myData.data[i - 1] + myData.data[i - 2] + myData.data[i - 3]) / 3
myData.data[i - 1] = myData.data[i - 2] = myData.data[i - 3] = total

ctx.putImageData(myData, 0, 0)是将处理后的像素点又绘制到画布上

结果

img

总结

以上就是canvas对图片的一些操作能力, 另外水平有限, 写的不好请谅解

最后

写的真的有点晕, 最后有点潦草了

img