先讲大致流程监听input表单变化读取文件 -> file.size若超出大小 -> canvas图片压缩 -> 用Blob,base64转二进制对象 -> 二进制对象转文件 -> formData 上传
html部分
<input :id="id" class="uploadIpt" type="file" accept="image/*" @change="previewImg($event)" capture="camera" ref="upload">
使用,监听表单变化,触发图片上传
let compress = new Compress()
compress.getImgData(e, (res) => {
this.onBeforceUpload(res) // 上传
this.$refs.upload.value = null // 清空表单
})
图片文件读取,判断是否需要压缩
getImgData(e, limit, callback) {
let file = event.target.files[0]
// 图片格式
if (['jpeg', 'png', 'gif', 'jpg'].indexOf(this.fileType.split('/')[1]) < 0) {
return { error: '图片格式错误' }
}
// 在部分ios压缩会有问题
let u = navigator.userAgent
let isIos = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
if (isIos) {
callback(this.file)
return
}
let r = new FileReader()
r.readAsDataURL(file)
r.onload = () => {
if (r.result) {
let base64 = r.result
let maxSize = limit * 1024
let fileSize = file.size / 1024
if (limit && fileSize > maxSize) {
// 一位小数(不四舍五入)
this.getCompress(base64).then((res) => {
let upfile = processData(res)
callback(upfile)
})
} else {
callback(file)
}
}
}
}
使用canvas 绘制,输出为base64
getCompress(dataURL) {
return new Promise((resolve, reject) => {
let that = this
const img = new window.Image()
img.onload = function() {
let [drawWidth, drawHeight] = [this.naturalWidth, this.naturalHeight]
let maxSide = Math.max(drawWidth, drawHeight)
// 最长的边大于1024,则等比缩放长边为1024
if (maxSide > 1024) {
let minSide = Math.min(drawWidth, drawHeight)
minSide = minSide / maxSide * 1024
maxSide = 1024
if (drawWidth > drawHeight) {
drawWidth = maxSide
drawHeight = minSide
} else {
drawWidth = minSide
drawHeight = maxSide
}
}
let canvas = document.createElement('canvas')
canvas.width = drawWidth
canvas.height = drawHeight
let context = canvas.getContext('2d')
context.clearRect(0, 0, drawWidth, drawHeight)
context.drawImage(this, 0, 0, drawWidth, drawHeight)
resolve(canvas.toDataURL(that.fileType, 0.8)) // 这里0.8可以选择自定义
}
img.src = dataURL
})
}
将base64 转为文件
processData(dataURL) {
// 这里使用二进制方式处理dataUrl
const bytes = window.atob(dataURL.split(',')[1])
const ab = new ArrayBuffer(bytes.length)
const ia = new Uint8Array(ab)
const type = this.file.type
const imgFile = this.file
for (let i = 0, j = bytes.length; i < j; i++) {
ia[i] = bytes.charCodeAt(i)
}
let blob
try {
blob = new Blob([ia], { type })
} catch (error) {
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder
if (error.name === 'TypeError' && window.BlobBuilder) {
let Builder = window.BlobBuilder
const builder = new Builder()
builder.append(ab)
blob = builder.getBlob(type)
} else {
// Toast.error("版本过低,不支持上传图片", 2000, undefined, false);
throw new Error('版本过低,不支持上传图片')
}
}
// blob 转file
const fileOfBlob = new File([blob], imgFile.name, { type })
return fileOfBlob
}