zoukankan      html  css  js  c++  java
  • H5图片压缩与上传

    接到需求,问前端是否可以压缩图片?因为有的图片太大,传到服务器上再压缩太慢了。意识里没有这么玩过,早上老大丢来一个知乎链接,一看,原来前辈们已经用canvas实现了(为自己的见识羞愧3秒钟,再马上开干)!。

    canvas压缩

    使用了github上的一个现成库:https://github.com/stomita/ios-imagefile-megapixel,不得不膜拜下stomita这位大神。大体的思路是将图片抽样显示在canvas上,然后用通过canvas.toDataURL方法得到base64字符串来实现压缩。比如在input元素触发change事件之后,读取里面的文件进行操作:

    var fileInput = document.getElementById('fileInput');
      fileInput.onchange = function() {
        var file = fileInput.files[0];
        // 创建一个压缩对象,该构造函数接收file或者blob。
        var mpImg = new MegaPixImage(file);
    // render方法的maxWith,maxHeight,以及quality都决定了压缩图片的质量 var resImg = document.getElementById('resultImage'); mpImg.render(resImg, { maxWidth: 300, maxHeight: 300, quality: 0.5 }); };

    压缩完成会得到类似这样的图片:

    data:image/jpeg 这样的格式已经应用的很多了,很多样式里面的背景图片直接就是这样。

    需要说明的是有两点,这里的resImg是一个预览图片,是已经存在于文档中的,如果你不需要预览,而只是创建一个img用来压缩(document.createElement("img")),这会少一个tagName属性。你可以修改源码或者自己加上这个属性。源码中会根据tagName进行判断,不存在的话会报错:

     MegaPixImage.prototype.render = function (target, options, callback) {
            //....
            target.tagName = target.tagName || "IMG"; //加上这一句
            var tagName = target.tagName.toLowerCase();
            if (tagName === 'img') {
                target.src = renderImageToDataURL(this.srcImage, opt, doSquash);
            } else if (tagName === 'canvas') {
                renderImageToCanvas(this.srcImage, target, opt, doSquash);
            }
            if (typeof this.onrender === 'function') {
                this.onrender(target);
            }
            if (callback) {
                callback();
            }
            if (this.blob) {
                this.blob = null;
                URL.revokeObjectURL(this.srcImage.src);
            }
        };

    另外这是一个耗时的操作,如果是多张图片进行压缩,不能直接调用,需要稍微变换一下,不然会导致前面的图片没有压缩完成就进入到了后面的图片。

     fileSelected: function () {
                        var files = $("#fileImage")[0].files;
                        var count = files.length;
                        console.log("共有" + count + "个文件");
                        for (var i = 0; i < count; i++) {var item = files[i];
                            console.log("原图片大小", item.size);
                            if (item.size > 1024 * 1024 * 2) {
                                console.log("图片大于2M,开始进行压缩...");
    
                                (function(img) {
                                    var mpImg = new MegaPixImage(img);
                                    var resImg = document.createElement("img");
                                    resImg.file = img;
                                    mpImg.render(resImg, { maxWidth: 500, maxHeight: 500, quality: 1 }, function() {
                                      //do some thing
                                    });
                                })(item);
    
                            } 
                            core.previewImage(item);
                        }
                    },

    上传处理

     1.直接post base64字符串

      uploadBase64str: function (base64Str) {
                        var formdata = new FormData();
                        formdata.append("base64str", base64Str);
                        var xhr = new XMLHttpRequest();
                        xhr.upload.addEventListener("progress", function (e) {
                            var percentComplete = Math.round(e.loaded * 100 / e.total);
                            para.onProgress(percentComplete.toString() + '%');
                        });
                        xhr.addEventListener("load", function (e) {
                            para.uploadComplete(xhr.responseText);
                        });
                        xhr.addEventListener("error", function (e) {
                            para.uploadError(e);
                        });
    
                        xhr.open("post", para.base64strUrl, true);
                        xhr.send(formdata);
                    },

    比如这里base64strUrl是/home/MUploadImgBase64Str,MVC控制器方法如下:

     [HttpPost]
            public ActionResult MUploadImgBase64Str(string base64str)
            {
                try
                {
                    var imgData = base64str.Split(',')[1];
                    //过滤特殊字符即可   
                    string dummyData = imgData.Trim().Replace("%", "").Replace(",", "").Replace(" ", "+");
                    if (dummyData.Length % 4 > 0)
                    {
                        dummyData = dummyData.PadRight(dummyData.Length + 4 - dummyData.Length % 4, '=');
                    }
                    byte[] byteArray = Convert.FromBase64String(dummyData);
                    using (System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray))
                    {
                        var img = System.Drawing.Image.FromStream(ms);
    
                        var path = "~/Content/UploadFiles/mobile/";
                        var uploadpath = Server.MapPath(path);
                        if (!Directory.Exists(uploadpath))
                        {
                            Directory.CreateDirectory(uploadpath);
                        }
                        var saveName = uploadpath + “stoneniqiu” + ".jpg";
                        img.Save(saveName);
                        return Json(saveName);
                    }
                }
                catch (Exception e)
                {
                    return Json(e.Message);
    
                }
            }

    几M的图片能压缩到几十k或者几百k,当然,如果宽度、高度和质量设置的太小,图片就会很失真了。这个字符串怎么获取呢?有两个方法,一个是直接读取src:

     var base641 = resImg.src;

    一个是用canvas转换:

     function getBase64Image(img) {
                    var canvas = document.createElement("canvas");
                    canvas.width = img.width;
                    canvas.height = img.height;
    
                    var ctx = canvas.getContext("2d");
                    ctx.drawImage(img, 0, 0, img.width, img.height);
    
                    var dataURL = canvas.toDataURL("image/jpeg");
                    return dataURL;
    
                    // return dataURL.replace("data:image/png;base64,", "");
                }
     var base64 = getBase64Image(resImg);

    同一张图片,这两者获取到的字符串大小不一样,但图片质量我是分辨不出什么差别。

    比如一个2M的图片,通过getBase64Image方法读到的字符串大小才64k,而src直接读取到的却是270k,各自生成的图片更小。一下分别是原图(2.2M),base64(48k),src(202k)对应的图片。

       

    getBase64Image通过canvas的toDataURL 获取到更小的base64字符串。

    2.也可以在前端转换blob对象,再post到后端

     function dataURItoBlob(dataUrl) {
                  
                    var byteString = atob(dataUrl.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); } return new Blob([ab], { type: 'image/jpeg' }); }

    3.不压缩的就直接装到formdata中,send到后台。

       uploadFile: function (file) {
                        console.log("开始上传");
                        var formdata = new FormData();
    
                        formdata.append(para.filebase, file);//这个名字要和mvc后台配合
    
                        var xhr = new XMLHttpRequest();
                        xhr.upload.addEventListener("progress", function (e) {
    
                            var percentComplete = Math.round(e.loaded * 100 / e.total);
                            para.onProgress(percentComplete.toString() + '%');
                        });
                        xhr.addEventListener("load", function (e) {
                            para.uploadComplete(xhr.responseText);
                        });
                        xhr.addEventListener("error", function (e) {
                            para.uploadError(e);
                        });
    
                        xhr.open("post", para.url, true);
        
                        xhr.send(formdata);
                    },

    全部的代码:(包含压缩和上传以及demo):

    github:https://github.com/stoneniqiu/h5upload/

    小结:基本上就是这样了,前端能够压缩图片的话,确实省了流量和时间。 插件是在上一篇的基础上进行改进的。

  • 相关阅读:
    QOMO Linux 4.0 正式版发布
    LinkChecker 8.1 发布,网页链接检查
    pgBadger 2.1 发布,PG 日志分析
    Aletheia 0.1.1 发布,HTTP 调试工具
    Teiid 8.2 Beta1 发布,数据虚拟化系统
    zLogFabric 2.2 发布,集中式日志存储系统
    开源电子工作套件 Arduino Start Kit 登场
    Piwik 1.9 发布,网站访问统计系统
    Ruby 1.9.3p286 发布,安全修复版本
    toBraille 1.1.2 发布,Java 盲文库
  • 原文地址:https://www.cnblogs.com/stoneniqiu/p/5957356.html
Copyright © 2011-2022 走看看