H5拍照、预览、压缩、上传采坑记录
公司项目前段时间需要实现手机拍照上传的功能,本来以为用和canvas可以很轻松的实现,结果发现问题多多,特此记录下来。
图片预览
在IOS上,竖着拍照片时,图片预览会旋转90°,横着拍照就没问题,我实验了一下,在IOS上,只有当图片的分辨率过大会出现这种情况。
最后实现图片预览效果借助了和,exif-js
负责读取图片的EXIF信息,获取orientation
信息,然后用megapix-image
把图片数据渲染在img标签上,代码如下:
import EXIF from '../utils/exif';import MegaPixImage from '../utils/megapix-image'; /** * * @param file file对象 * @param resImg 预览IMG标签 * @returns {Promise} */ renderPreviewImg(file, resImg) { return new Promise(function (resolve, reject) { EXIF.getData(file, _=> { var allMetaData = EXIF.getAllTags(file); var orientation = allMetaData.Orientation; var mpImg = new MegaPixImage(file); mpImg.render(resImg, { maxWidth: 1024, maxHeight: 1024, // quality: 0.6, orientation: orientation }, resolve); }); }); }
无刷新压缩上传
思路有两种:
用canvas的API,直接将base64文本传递过去
自己构造File对象,ajax上传
第一种方法需要服务器端做工作,而且上传数据量会增大4/3,因此此方法只作为回退方案。
第二种方法的原理是用Uint8Array来构造Blob,再使用formData上传。
这里要注意的是:ArrayBuffer
不能被直接操作,必须通过typed array
来存取,而且的构造函数也是typed array
。 完整代码如下:
this.renderPreviewImg(file, resImg) .then(() => { try { var binaryData = null; if (!Blob || !ArrayBuffer || !Uint8Array) { // alert(123); binaryData = file;//如果不支持压缩,直接上传原始图片 } else { //组装二进制 var base64Data = $(resImg).attr('src'); var byteString = atob(base64Data.split(',')[1]); var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } binaryData = new Blob([ia], { "type": file.type }); } this.setState({ uploadProgress: 0 }); //组装formData var fd = new FormData(); fd.append('file', binaryData, 'img.jpg'); fd.append('token', uploadToken); console.log(fd); return this.uploadBinaryDataToQiniu(fd, this.uploadSuccess.bind(this), this.handleUploadProgress.bind(this)) } catch (e) { alert(e.message); } }).catch(function (e) { console.log(e); })