图片压缩上传


/**
* @Date: 2016/11/17 0017
* @Time: 10:14
* @Author: lxbin
*
* Created with JetBrains WebStorm.
*/

/**
* http://leonshi.com/2015/10/31/html5-canvas-image-compress-crop/
* http://jafeney.com/2016/08/11/20160811-image-upload/
* http://ilovetile.com/3506
*/

/**
* 读取文件
* @param file 文件对象
* @return {Promise}
*/
function readFileAsync(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = e => resolve(readFile.target.result)
reader.onerror = e => reject(new Error('Could not read file'))
reader.readAsDataURL(file)
})
}

/**
* 加载图片
* @param url 图片地址
* @return {Promise}
*/
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = () => resolve(image)
image.onerror = () => reject(new Error('Could not load image at ' + url))
image.src = url
})
}

/**
* base64的图片dataUri转Blob
* @param dataURI
* @return {*}
*/
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
const byteString = atob(dataURI.split(',')[1]);

// separate out the mime component
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

// write the bytes of the string to an ArrayBuffer
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

// write the ArrayBuffer to a blob, and you're done
return new Blob([ab], {type: mimeString});

// Old code
// const bb = new BlobBuilder();
// bb.append(ab);
// return bb.getBlob(mimeString);
}

/**
* 图片转Blob
* @param image 图片对象
* @param quality 图片质量(0到1之间)
* @param scale 缩放比例(0到1之间)
* @return {Promise}
*/
function imageToBlob(image, quality, scale) {
return new Promise((resolve, reject) => {
try {
let canvas = document.createElement('canvas')
canvas.width = image.naturalWidth * scale
canvas.height = image.naturalHeight * scale
while (canvas.width >= 3264 || canvas.height >= 2448) {//超过这个值base64无法生成,在IOS上
canvas.width = canvas.naturalWidth * scale
canvas.height = canvas.naturalHeight * scale
}

let ctx = canvas.getContext('2d').drawImage(image, 0, 0, canvas.width, canvas.height)

//方式一:低版本兼容性差些
//canvas.toBlob(function (blob) {
// console.group('[Leo]file compress to blob')
// console.log('文件类型 => ' + image.type)
// console.log('文件大小 => ' + (image.size / 1024 / 1024).toFixed(2) + 'M')
// console.log('blob质量 => ' + quality)
// console.log('blob大小 => ' + (blob.size / 1024 / 1024).toFixed(2) + 'M')
// console.groupEnd()
// resolve(blob)
//}, 'image/jpeg', quality)

//方式二:
const base64 = canvas.toDataURL('image/jpeg', quality);
const blob = dataURItoBlob(base64);
blob.name = blob.filename = image.name
console.group('[Leo]image compress to blob')
console.log('文件类型 => ' + image.type)
console.log('文件大小 => ' + (image.size / 1024 / 1024).toFixed(2) + 'M')
console.log('blob质量 => ' + quality)
console.log('blob大小 => ' + (blob.size / 1024 / 1024).toFixed(2) + 'M')
console.groupEnd()
resolve(blob);
} catch (e) {
reject(new Error("Image could not convert to blob :" + e))
}
})
}

/**
* Ajax上传
* @param uri 上传的Action地址
* @param file 文件对象
* @return {Promise}
*/
function uploadFile(uri, file) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
if (xhr.upload) {
xhr.upload.addEventListener("progress", (e) => {// 处理上传进度
if (e.lengthComputable) {
let percent = (e.loaded / e.total * 100).toFixed(2) + '%'
console.log("上传中(" + percent + ")");
//TODO:反馈到DOM里显示
} else {
console.log('unable to compute');
}
}, false)
}
xhr.onreadystatechange = (e) => {// 文件上传成功或是失败
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.responseText)// 上传成功
} else {
reject(xhr.responseText)// 上传出错处理
}
}
}
xhr.open("POST", uri, true)// 开始上传
let form = new FormData()
form.append("filedata", file, file.name)
xhr.send(form)
})
}

/**
* 上传文件
* @param file 文件对象
* @param quality 图片质量(0到1之间)
* @param scale 缩放比例(0到1之间)
*/
export default async function fileUpload(file, quality, scale) {
try {
let fileUrl = await readFileAsync(file)
let image = await loadImageAsync(fileUrl)
image.name = file.name
let blob = await imageToBlob(image, quality, scale)
let upload = await uploadFile(blob)
return upload
} catch (e) {
console.log('file upload failed')
}
}

参考:
http://leonshi.com/2015/10/31/html5-canvas-image-compress-crop/
http://jafeney.com/2016/08/11/20160811-image-upload/
http://ilovetile.com/3506

坚持原创技术分享,您的支持将鼓励我继续创作!