在日常开发中多多少少会碰到用户上传图片的场景,随着拍照设备的提升,越来越多大尺寸照片诞生,无论是存储空间对于服务器压力,还是传输速率对于用户体验都有着很大的影响。
要把一张图从大变小,马上能想到的就是三步曲:转换格式、缩小尺寸、降低画质,大多数情况下 转换格式 能达到比较好的效果(如 png 转 jpeg / webp)。
那么,要如何在端上完成图片压缩呢?
通过了解 Canvas 的 API 可以知道,Canvas 可以绘制图片,调整尺寸、区域裁剪、设置图片画质*(仅 jpg、webp)*,最重要的它还可以输出指定格式的图片文件。
简单实现
获取文件
在 <input /> 选择图片后获取到文件信息,通过 FileReader 来进一步将图片读取成 base64
// ...
inputChanged = (e) => {
let that = this
let file = e.target.files[0]
// 通过 FileReader 读取文件
let reader = new FileReader()
reader.readAsDataURL(file)
// 在读取完成后进行下一步处理
reader.onload = function (e) {
// src 是 base64
let src = e.target.result
console.log(src)
// 下一步要对src进行处理
that.dealImage(src)
}
}
render() {
return (
<div>
<input onChange={this.inputChanged} type="file" />
</div>
)
}
读取图片
通过 Image 对象加载上一步的 base64 图片,然后在图片的 onload 后进行 Canvas 操作
// ...
dealImage = (src) => {
let that = this
let image = new Image()
image.src = src
image.onload = function () {
// 通过 Canvas 操作来处理图片
that.compressImage(image)
}
}
Canvas处理
// ...
compressImage = (image) => {
// 创建 canvas 节点
let canvas = document.createElement('canvas')
// 获取 canvas 操作对象
let ctx = canvas.getContext('2d')
// 读取原始图片尺寸
let imageW = image.width, imageH = image.height
// 指定输出图片尺寸, 按比例,比如限制宽是1024
let afterW = 1024, afterH = afterW * imageH / imageW
// 设置 canvas 画布大小
canvas.width = imageW
canvas.height = imageH
// -----进行处理
// 不压缩
// drawImage(image, dx, dy)
ctx.drawImage(image, 0, 0)
// 压缩到指定尺寸
// drawImage(image, dx, dy, dWidth, dHeight)
ctx.drawImage(image, 0, 0, afterW, afterH)
// 按位置截取并压缩
// drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
ctx.drawImage(image, 20, 30, 50, 60, 0, 0, afterW, afterH);
// -----输出结果
// 类型默认png,可选jpeg、webp
// - 获取处理后的 base64 数据
let data = canvas.toDataURL('image/jpeg', 0.8)
console.log(data)
// - 转成 blob 并在回调中进行下一步操作
canvas.toBlob(function (blob) {
// 操作 blob,做上传之类的
console.log(blob)
}, 'image/webp', 0.8)
}
drawImage
入参形式有以下三种, 具体释义可看 Canvas - drawImage()
drawImage(image, dx, dy)drawImage(image, dx, dy, dWidth, dHeight)drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
结合下图还是能很快理解各个参数含义的

获取结果
可以通过 toDataURL(mimeType, quality) 和 toBlob(callback, mimeType, quality) 来获取处理结果
在输出时,可以设置 mineTpye 来转换格式,默认是 png,如果是 jpeg 和 webp 的话还可以设置质量
具体可查阅: Canvas - toDataURL() Canvas - toBlob()
现成方案
除了自己手动撸一个图片压缩处理,当然也有更快更直接的现成方案
上传前压缩图片
使用 compressorjs 可以在上传前对图片进行多种操作以达到压缩图片大小的目的,具体用法可以参阅其 Readme文档。
下载压缩图片
国内常用的七牛云存储图片资源,通过了解官方文档 七牛-图片高级处理 ,七牛以直接获取经过 格式转换、裁切、降画质、缩略图、旋转 等 操作后的图片。