压缩图片原理
- 通过原生的input标签拿到要上传的图片文件
- 将图片文件转化成img元素标签
- 在canvas上压缩绘制该HTMLImageElement
- 将图片转化为一个包含图片展示的data URI,即图片被转换成base64编码的字符串
实现
通过原生的input标签拿到上传的图片文件
- css部分
<input ref="image" type="file" accept="image/*" @change="getFile" />
- 图片上传后通过以下代码拿到上传的图片文件,这里拿到的为FileList文件对象数组,如下图所示。因为我们这里是单文件上传,因此直接取数组中第一个file对象就是我们上传的图片文件
this.$refs.image.files[0]
将图片文件转化成img元素标签
-
由于通过input拿到的文件是file对象类型的,在压缩之前需要转化为img对象,通过以下方法即可
fileToImg (file) { return new Promise((resolve, reject) => { const img = new Image() const reader = new FileReader() reader.onload = function (e) { img.src = e.target.result } reader.onerror = function (e) { reject(e) } reader.readAsDataURL(file) img.onload = function () { resolve(img) } img.onerror = function (e) { reject(e) } }) }
在canvas上压缩绘制该HTMLImageElement,将图片转换成base64编码的字符串
-
将图片转化为img对象后,就可以创建canvas对象,在canvas上压缩绘制合适宽高的图片。这里分为两种情况:
- 将图片压缩为指定高度
/** * 压缩图片 * @param img 被压缩的img对象 * @param height 触发压缩的图片固定高度 */ compressImgHeight (img, height) { return new Promise((resolve) => { // 创建canvas对象 const canvas = document.createElement('canvas') const context = canvas.getContext('2d') // 获取上传的img图片对象的宽度和高度 const { width: originWidth, height: originHeight } = img // 绘制图片的高度 canvas.height = height // 根据绘制图片的高度,等比例计算图片的宽度 canvas.width = (originWidth * canvas.height) / originHeight // 将img绘制到画布上 context.drawImage(img, 0, 0, canvas.width, canvas.height) // 转为一个包含图片展示的data URI,即图片被转换成base64编码的字符串,格式为jpeg // 0.8为图片质量,区间为0~1,默认0.92 resolve(canvas.toDataURL('image/jpeg', 0.8)) }) },
- 将图片压缩为指定宽度
/** * 压缩图片 * @param img 被压缩的img对象 * @param width 触发压缩的图片固定宽度 */ compressImgHeight (img, width) { return new Promise((resolve) => { // 创建canvas对象 const canvas = document.createElement('canvas') const context = canvas.getContext('2d') // 获取上传的img图片对象的宽度和高度 const { width: originWidth, height: originHeight } = img // 绘制图片的宽度 canvas.width = width // 根据绘制图片的宽度,等比例计算图片的高度 canvas.height = (originHeight * canvas.width) / originWidth // 将img绘制到画布上 context.drawImage(img, 0, 0, canvas.width, canvas.height) // 转为一个包含图片展示的data URI,即图片被转换成base64编码的字符串,格式为jpeg // 0.8为图片质量,区间为0~1,默认0.92 resolve(canvas.toDataURL('image/jpeg', 0.8)) }) }
总结
- 将以上代码进行总结
// css部分 <input ref="image" type="file" accept="image/*" @change="getFile" /> // js部分 getFile () { this.readImg(this.$refs.image.files[0]).then(res => { // 压缩图片为指定宽度 this.compressImgHeight(res, 300).then(img => { // 输出压缩后的图片base64 console.log(img) }) }) } /** * 将图片file对象转化为img对象 * @param file 图片file对象 */ fileToImg (file) { return new Promise((resolve, reject) => { const img = new Image() const reader = new FileReader() reader.onload = function (e) { img.src = e.target.result } reader.onerror = function (e) { reject(e) } reader.readAsDataURL(file) img.onload = function () { resolve(img) } img.onerror = function (e) { reject(e) } }) }, /** * 压缩图片为指定宽度 * @param img 被压缩的img对象 * @param width 触发压缩的图片固定宽度 */ compressImgWidth (img, width) { return new Promise((resolve) => { // 创建canvas对象 const canvas = document.createElement('canvas') const context = canvas.getContext('2d') // 获取上传的img图片对象的宽度和高度 const { width: originWidth, height: originHeight } = img // 绘制图片的宽度 canvas.width = width // 根据绘制图片的宽度,等比例计算图片的高度 canvas.height = (originHeight * canvas.width) / originWidth // 将img绘制到画布上 context.drawImage(img, 0, 0, canvas.width, canvas.height) // 转为一个包含图片展示的data URI,即图片被转换成base64编码的字符串,格式为jpeg // 0.8为图片质量,区间为0~1,默认0.92 resolve(canvas.toDataURL('image/jpeg', 0.8)) }) }, /** * 压缩图片为指定高度 * @param img 被压缩的img对象 * @param height 触发压缩的图片固定高度 */ compressImgHeight (img, height) { return new Promise((resolve) => { // 创建canvas对象 const canvas = document.createElement('canvas') const context = canvas.getContext('2d') // 获取上传的img图片对象的宽度和高度 const { width: originWidth, height: originHeight } = img // 绘制图片的高度 canvas.height = height // 根据绘制图片的高度,等比例计算图片的宽度 canvas.width = (originWidth * canvas.height) / originHeight // 将img绘制到画布上 context.drawImage(img, 0, 0, canvas.width, canvas.height) // 转为一个包含图片展示的data URI,即图片被转换成base64编码的字符串,格式为jpeg // 0.8为图片质量,区间为0~1,默认0.92 resolve(canvas.toDataURL('image/jpeg', 0.8)) }) }