canvas 可以直接将图像渲染到画布上,并对图像进行旋转、变形、滤镜处理。
一、导入图片
首先我们需要导入一张图片,有几种方式:
本地方式:
通过下面两种方式获取 file:
- 设置一个拖放区域,将本地的图片拖放进去:
drop事件中获取event.dataTrnsfer.files - 通过
<input type="file" />标签,change事件获取event.target.files
然后,实例一个 FileReader,用 readAsDataURL(file) 来读取文件。当读取完成,触发 load 事件,可获取到 base64 的编码:
const reader = new FileReader()
reader.addEventListener('load', event => {
console.log(event.target.result) // data:URL 格式的字符串(base64 编码)
})
reader.readAsDataURL(file)
远程数据:
上传,或者直接选择一个网络图片,获取其 url
二、将图片绘制到画布上
首先需要 new 一个 Image 对象 img,但它不需要插入到 dom 中。设置 src 属性和 load 事件。
然后通过 canvas 的 context 的 drawImage 方法来将 img 对象渲染到画布上。注意这个方法有多种参数形式,是可以对图片渲染进行缩放、裁切和定位。
const img = new Image()
img.addEventListener('load', () => {
ctx.drawImage(img)
})
img.src = result // 这个 result 可以是 data:URL 格式字符串,或者 url
三、像素处理
获取 ImageData
要进行像素处理,需要先了解 ImageData 对象。它是描述图像像素信息的对象。我们可以通过 getImageData 从 ctx 上获取:
const myImageData = ctx.getImageData(left, top, width, height)
它有三个属性:
width:横向的像素height:纵向的像素data:Uint8ClampedArray这样的数据结构,和数组非常类似。它记录着所有的像素信息:- 每四个成员表示一个像素,分别代表它的 r,g,b,a
- 每个成员取值是 [0,255],赋值如果超出则会被替代为 0 或 255,所以没有必要使用
Math.min(value, 255)这样的方式去限定它
处理 ImageData
滤镜,其实就是对每个像素的 r,g,b,a 进行重新赋值。
灰度
一般有几种算法:
- 取 rgb 的平均值
- 取 rgb 的最大值
- 使用加权公式:
0.3 * r + 0.59 * g + 0.11 * b
比如采用平均值算法:
const { data } = imageData
// 先需要把元数据备份一份
const dataSource = [ ...data ]
// 直接修改 imageData.data 的值
function changeGray(percent) {
for (let i = 0; i < dataSource.length; i += 4) {
const avg = (dataSource[i] + dataSource[i + 1] + dataSource[i + 2]) / 3;
data[i] = Math.min(dataSource[i] + (avg - dataSource[i]) * percent, 255); // red
data[i + 1] = Math.min(dataSource[i + 1] + (avg - dataSource[i + 1]) * percent, 255); // green
data[i + 2] = Math.min(dataSource[i + 2] + (avg - dataSource[i + 2]) * percent, 255); // blue
}
}
黑白
黑白就是 rgb 的平均值,大于 255 / 2 就给这三位赋值 255,否则就是 0
反色
反色就是 rgb 分别赋值 255 - value
模糊
每个像素点和周围像素点互相影响
让改动生效
使用 ctx.putImageData(imageData, 0, 0) 让改动后的 imageData 在画布上生效
四、生成 base64 及下载
直接调用 canvas.toDataURL() 方法,可以将画布转化为 base64 的编码的字符串。这个方法可以接受这两参数:
type(可选):默认为image/png,也可以传入image/jpeg和image/webp(chrome 专属)encoderOptions(可选): jpeg 和 webp 的格式可以设置图片质量,取值 0 ~ 1 之间
生成的 base64 我们可以用来下载,除了用户自己右键下载,或者我们通过服务器来返回下载外,我们还可以生成个 a 标签,直接下载:
downloadImage(name) {
const a = document.createElement('a');
a.href = canvas.toDataURL();
a.download = name ? name : '下载'
a.click()
}