JS图片压缩
注意:本文中图片压缩方法只能将压缩后的图片固定保存为 “image/jpeg” 格式,不能设置为 “image/png” 格式(该格式压缩无效)。
具体代码如下
压缩相关的方法:
/** * 文件转base64 * @param {File} file 需要转换的文件 * @param {Function} callback 回调函数, 执行回调后返回 base64 格式图片 */export function imageToBase64(file, callback) { const reader = new FileReader() reader.readAsDataURL(file) // 文件转base64 reader.addEventListener('load', e => { callback && callback(e.target.result) })}/** * base64 类型转 Blob 类型 * @param {base64} base64 * @returns {Blob} blob */export function base64ToBlob(base64) { let arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } return new Blob([u8arr], { type: mime })}/** * 压缩图片 * @param {base64} originalImage 转换为 base64 的原始图片 * @param {Number} compressRatio 压缩比例 0 - 1, 1则不压缩 * @param {Function} callback 回调方法, 执行回调后返回 base64 格式图片 */export function compressImg(originalImage, compressRatio = 1, callback) { const image = new Image() image.src = originalImage /* 监听图片的load事件 */ image.addEventListener('load', function() { let [sizeRatio, maxWidth, maxHeight] = [0, 1024, 1024] // 图片压缩宽高比例和最大宽高 let [imageWidth, imageHeight] = [this.naturalWidth, this.naturalHeight] // 图片实际宽高 let compressFlag = false // 图片是否需要压缩 // 如果图片宽度大于最大宽度就等比压缩图片的高度 if (imageWidth > maxWidth) { compressFlag = true sizeRatio = imageWidth / maxWidth maxHeight = imageHeight / sizeRatio } // 如果图片高度大于最大高度就等比压缩图片的宽度 if (imageHeight > maxHeight) { compressFlag = true sizeRatio = imageHeight / maxHeight maxWidth = imageWidth / sizeRatio } // 如果不需要压缩 if (!compressFlag) { maxWidth = imageWidth maxHeight = imageHeight } // 使用canvas压缩图片 const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') canvas.setAttribute('id', 'canvas') canvas.width = maxWidth canvas.height = maxHeight ctx.clearRect(0, 0, maxWidth, maxHeight) // 清除画布内所有像素 ctx.drawImage(image, 0, 0, maxWidth, maxHeight) // canvas绘制当前图片 const compressImage = canvas.toDataURL('image/jpeg', compressRatio) // 设置压缩类型和压缩比例获取压缩后的文件, 为 base64 callback && callback(compressImage) })}
业务中使用,我这里用的 vue,这里只展示了部分代码(大家只需关注 isCompressImg 方法)
beforeRead(file) { if (file.type !== 'image/jpeg' && file.type !== 'image/png') { this.$toast('请上传 jpg 或 png 格式图片') return false } return true},afterRead(file) { file.status = 'uploading' file.message = '上传中...' this.btnDisabled = true const imgFile = file.file this.isCompressImg(imgFile, img => { // 此时可以自行将文件上传至服务器 alyOSS .ossUploadFile({ file: img }) .then(res => { this.fileList = [ { url: res.url } ] file.status = 'done' file.message = '' }) .catch(() => { file.status = 'failed' file.message = '上传失败' }) .finally(() => { this.btnDisabled = false }) })},// 判断是否需要压缩isCompressImg(file, callback) { const maxSize = 1 * 1024 * 1024 // 最大 1M // 压缩图片 if (file.size > maxSize) { imageToBase64(file, originalImage => { compressImg(originalImage, 0.5, compressImage => { // base64 转 blob, blob 再转 file const img = new File([base64ToBlob(compressImage)], file.name, { type: file.type }) // 递归判断, 防止压缩后的图片仍然大于 1M this.isCompressImg(img, f => { callback(f) }) }) }) } else { callback(file) }},