2

H5拍照、预览、压缩、上传采坑记录

公司项目前段时间需要实现手机拍照上传的功能,本来以为用createObjectURL和canvas可以很轻松的实现,结果发现问题多多,特此记录下来。

DEMO预览(需用新标签页打开)

图片预览

在IOS上,竖着拍照片时,图片预览会旋转90°,横着拍照就没问题,我实验了一下,在IOS上,只有当图片的分辨率过大会出现这种情况。

最后实现图片预览效果借助了exif-jsmegapix-imageexif-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);

            });
        });


    }

无刷新压缩上传

思路有两种:

  1. 用canvas的toDataURL()API,直接将base64文本传递过去

  2. 自己构造File对象,ajax上传

第一种方法需要服务器端做工作,而且上传数据量会增大4/3,因此此方法只作为回退方案。

第二种方法的原理是用Uint8Array来构造Blob,再使用formData上传。
这里要注意的是:ArrayBuffer不能被直接操作,必须通过typed array来存取,而且Blob的构造函数也是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);
        })

参考文章

http://tgideas.qq.com/webplat...

http://blog.csdn.net/hsany330...


Larry_
704 声望186 粉丝

FE