Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

移动端H5图片上传的那些坑 #6

Open
CommanderXL opened this issue Jan 4, 2019 · 0 comments
Open

移动端H5图片上传的那些坑 #6

CommanderXL opened this issue Jan 4, 2019 · 0 comments

Comments

@CommanderXL
Copy link
Owner

上周做一个关于移动端图片压缩上传的功能。期间踩了几个坑,在此总结下。

大体的思路是,部分API的兼容性请参照caniuse

  1. 利用FileReader,读取blob对象,或者是file对象,将图片转化为data uri的形式。
  2. 使用canvas,在页面上新建一个画布,利用canvas提供的API,将图片画入这个画布当中。
  3. 利用canvas.toDataURL(),进行图片的压缩,得到图片的data uri的值
  4. 上传文件。

步骤1当中,在进行图片压缩前,还是对图片大小做了判断的,如果图片大小大于200KB时,是直接进行图片上传,不进行图片的压缩,如果图片的大小是大于200KB,则是先进行图片的压缩再上传:

    <input type="file" id="choose" accept="image/*">
    var fileChooser = document.getElementById("choose"),
        maxSize = 200 * 1024;   //200KB
    fileChoose.change = function() {
        var file = this.files[0],   //读取文件
            reader = new FileReader();
            
            reader.onload = function() {
                var result = this.result,   //result为data url的形式
                    img = new Image(),
                    img.src = result;
                    
                    
                if(result.length < maxSize) {  
                    imgUpload(result);      //图片直接上传
                } else {
                    var data = compress(img);    //图片首先进行压缩
                    imgUpload(data);                //图片上传
                }
            }
            
            reader.readAsDataURL(file);
    }

步骤2,3:

    var canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');
        
    function compress(img) {
        canvas.width = img.width;
        canvas.height = img.height;
        
        //利用canvas进行绘图
        
        //将原来图片的质量压缩到原先的0.2倍。
        var data = canvas.toDataURL('image/jpeg', 0.2); //data url的形式
        
        return data;
    }

在利用canvas进行绘图的过程中,IOS图片上传过程中,存在着这样的问题:

  1. 当你竖着拿手机的时候,拍完照,上传图片时,会出现照片自动旋转的情况,而横着拍照并上传图片时不会出现这个问题。这个时候如果想纠正图片自动旋转的情况,将图片转化为二进制的数据(使用了binaryajax.js),方便获取图片的exif信息,通过获取exif的信息来确定图片旋转的角度(使用了exif.js),然后再进行图片相应的旋转处理。解决方法请戳我
  2. IOS中,当图片的大小大于 2MB时,会出现图片压扁的情况,这个时候需要重置图片的比例。解决方法请戳我
  3. 利用FileReader,读取图片的过程需要花费一定时间,将图片数据注入到canvas画布中需要一定时间,图片压缩的过程中,图片越大,CPU计算消耗的时间也越长,可能会出现顿卡的情况。总之,就是这个过程当中需要花费一定时间。
  4. IOS8.1的版本中有个FileReader的bug: FileReader读取的图片转化为Base64时,字符串为空,具体的问题描述请戳我

步骤4,文件上传有2种方式:

  1. 将图片转化为base64
  2. 将图片数据转为Blob对象,使用FormData上传文件

方式1可以通过xhr ajax或者xhr2 FormData进行提交。

方法2这里就有个大坑了。具体描述请戳我

简单点说就是:Blob对象是无法注入到FormData对象当中的。

当你拿到了图片的data uri数据后,将其转化为Blob数据类型

    var ndata = compress(img);
    ndata = window.atob(ndata); //将base64格式的数据进行解码
    
    //新建一个buffer对象,用以存储图片数据
    var buffer = new Uint8Array(ndata.length);
    for(var i = 0; i < text.length; i++) {
        buffer[i] = ndata.charCodeAt(i);
    }
    
    //将buffer对象转化为Blob数据类型
    var blob = getBlob([buffer]);
    
    var fd = new FormData(),
        xhr = new XMLHttpRequest();
    fd.append('file', blob);
    
    xhr.open('post', url);
    xhr.onreadystatechange = function() {
        //do something
    }
    xhr.send(fd);

在新建Blob对象中有需要进行兼容性的处理,特别是对于不支持FormData上传blob的andriod机的兼容性处理。具体的方法请戳我
主要实现的细节是通过重写HTTP请求。


2月19日更新

在安卓机器中,部分4.x的机型, 在webview里面对file对象进行了阉割,比如你拿不到file.type的值。

2月22日更新

Android4.4<input type="file">由于系统WebViewopenFileChooser接口更改,导致无法选择文件,从而导致无法上传文件. bug描述请戳我

封装好的github库,请戳我,如果觉得文章不错,请不要吝啬你的star~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant