layui中实现上传图片压缩

1、关于js上传图片压缩的方法,百度有不少种方法,这里我参考修改了一下:html

function photoCompress(file, w, objDiv) {
    var ready = new FileReader();
    /*开始读取指定的Blob对象或File对象中的内容. 当读取操做完成时,readyState属性的值会成为DONE,若是设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
    ready.readAsDataURL(file);
    ready.onload = function() {
        var re = this.result;
        canvasDataURL(re, w, objDiv);
    }
};
function canvasDataURL(path, obj, callback) {
    var img = new Image();
    img.src = path;
    img.onload = function() {
        var that = this;
        // 默认按比例压缩
        var w = that.width,
            h = that.height,
            scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        var quality = 0.5; // 默认图片质量为0.7
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        // 建立属性节点
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 图像质量
        if(obj.quality && obj.quality <= 1 && obj.quality > 0) {
            quality = obj.quality;
        }
        // quality值越小,所绘制出的图像越模糊
        var base64 = canvas.toDataURL('image/jpeg', quality);
        // 回调函数返回base64的值
        callback(base64);
    }
}
function convertBase64UrlToBlob(urlData) {
    var arr = urlData.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
    while(n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {
        type: mime
    });
}

以上是压缩图片的方法,核心是将图片放入canvas内,再用canvas.toDataURL方法进行压缩,最后生成一个Blob对象。node

注:由于牵扯到canvas,因此低版本浏览器应该是不支持的吧(有待考证)ajax

 

2、图片压缩的方法有了,怎么使用呢?怎么上传到后台呢?往下看!canvas

html部分:浏览器

   
        <form action="file/uploadDoc" enctype="multipart/form-data" method="post" id="form">
            <input type="file" id="file" name="file" />
            <input type="submit" value="上传" />
        </form>
 

 

 

js部分:async

      $("#file").change(function() {
                var formData = new formData("form");
                var file = this.files[0];
                photoCompress(file, {
                    quality: 0.5,
                }, function(base64Codes) {
                    var bl = convertBase64UrlToBlob(base64Codes);
                    formData.set("file", bl, file.name);
                });
            });

当选择文件之后,使用photoCompress方法对上传的图片进行压缩,photoCompress方法的第二个参数还能够传入长宽等参数,具体能够看photoCompress这个方法,quality是用来设置压缩后图片质量的,越小质量越差,表现出来就是图片越模糊,可是相应的体积就越小。ide

最后使用formData.set(key,value,name)方法,将现有的name为file的表单元素的值改变。这个方法有三个参数,第一个是key值,也就是表单里对应的元素的name值(若是不存在会自行添加),第二个值是value值,第三个是选填的值,若是第二个值为blob对象或者file对象,则第三个值表示文件名。函数

 

固然,若是你不想用form表单提交,你也能够用ajax提交的方法:post

html:   ui

 

        <form enctype="multipart/form-data" method="post" id="form">
            <input type="file" id="file" name="file" />
            <input type="button" value="上传" id="uploadBtn"/>
        </form>

 

 

 

有些许的变化,form没有了action,上传的按钮type改成了button

js部分给按钮添加一个点击事件,其余也没有变化,不作过多赘述:

            $("#uploadBtn").click(function () {
                var formData = new formData("form");
                $.ajax({
                    type:"post",
                    url:"",
                    async:true,
                    data:formData,
                    success:function (data) {
                        
                    },
                    error:function (e) {
                        
                    }
                });
            });

 

 

3、结合layui踩的一些坑,以及最终的解决方法。

先看html部分:

<button type="button" class="layui-btn" id="upImg">上传图片</button>
<div id="img_list">
</div>
<input type="button" id = "btnHide" class="none">

 

就是这么简单。为何要再写一个隐藏的按钮,以后解释。

js部分:

            layui.use('upload', function() {
                var upload = layui.upload;
                var uploadInst = upload.render({
                    elem: '#upImg',
                    url: '/upload/',
                    auto: false,
                    bindAction: "#btnHide",
                    choose: function(obj) {
                        var files = obj.pushFile();
                        var index, file, indexArr = [];
                        for(index in files) {
                            indexArr.push(index);
                        };
                        var iaLen = indexArr.length;
                        file = files[indexArr[iaLen - 1]];
                        for(var i = 0; i < iaLen - 1; i++) {
                            delete files[indexArr[i]];
                        }
                        try {
                            if(file.size > 200 * 1024) {
                                delete files[index];
                                photoCompress(file, {
                                    quality: 0.5,
                                }, function(base64Codes) {
                                    var bl = convertBase64UrlToBlob(base64Codes);
                                    obj.resetFile(index, bl, file.name);
                                    $("#btnHide").trigger("click");
                                });
                            } else {
                                $("#btnHide").trigger("click");
                            }
                        } catch(e) {
                            $("#btnHide").trigger("click");
                        }
                    },
                    done: function(res) {
                        //这里把后台返回的数据进行操做,展现上传完成的图片,具体数据格式参考layui的API
                    },
                    error: function() {

                    }
                });
            });

原理:在选择照片以后,获取文件,转换为blob对象,使用resetFile方法对文件列队里的文件进行从新设置,而后再触发上传事件。

踩的坑:

一、resetFile这个方法是layui 2.3.0 新增的,因此首先要确保layui的版本是最新的。

二、我把auto设置为false,点击btnHide时触发上传,我也试过自动上传,自动上传的话,这些操做的代码就要写在before方法中(具体看layui的API),然而我发现自动上传修改文件列队的方法老是在上传成功以后才调用,这就致使实际上传的图片其实没有压缩,至于为何是这个执行顺序我隐约以为是否是图片转码,放入canvas的时候耽误了……具体缘由我不明白,因此我用手动上传,确认修改了文件列队,再手动触发上传。

三、关于文件列队,屡次上传文件,文件列队也就是obj.pushFile()返回的是多个文件的对象,并且这些文件对象的key仍是一串随机数……因此个人思路是上传一次,就用delete方法删除队列中已上传过的文件。至于为何不直接所有清空,由于考虑到不须要压缩的状况,若是所有清空,不压缩,就没有执行resetFile方法,文件列队里就没有文件,会报错。

相关文章
相关标签/搜索