H5图片压缩与上传实例


Posted in Javascript onApril 21, 2017

接到需求,问前端是否可以压缩图片?因为有的图片太大,传到服务器上再压缩太慢了。意识里没有这么玩过,早上老大丢来一个知乎链接,一看,原来前辈们已经用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 }); 
 };
压缩完成会得到

类似这样的图片:

H5图片压缩与上传实例

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);

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

H5图片压缩与上传实例

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

H5图片压缩与上传实例H5图片压缩与上传实例H5图片压缩与上传实例

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/

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery替换textarea中换行的方法
Jun 10 Javascript
JS实现自动固定顶部的悬浮菜单栏效果
Sep 16 Javascript
基于Vue.js实现数字拼图游戏
Aug 02 Javascript
js实现的页面加载完毕之前loading提示效果完整示例【附demo源码下载】
Aug 02 Javascript
AngularJS API之copy深拷贝详解及实例
Sep 14 Javascript
详解angularjs中的隔离作用域理解以及绑定策略
May 31 Javascript
jQuery取得元素标签名称小结(附代码)
Aug 16 jQuery
详解webpack4升级指南以及从webpack3.x迁移
Jun 12 Javascript
详解javascript函数写法大全
Mar 25 Javascript
微信小程序云开发详细教程
May 16 Javascript
Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置
May 27 Javascript
在webstorm中配置less的方法详解
Sep 25 Javascript
H5手机端多文件上传预览插件
Apr 21 #Javascript
ES6新特性八:async函数用法实例详解
Apr 21 #Javascript
.net MVC+Bootstrap下使用localResizeIMG上传图片
Apr 21 #Javascript
jquery中$.fn和图片滚动效果实现的必备知识总结
Apr 21 #jQuery
ES6新特性七:数组的扩充详解
Apr 21 #Javascript
React中ES5与ES6写法的区别总结
Apr 21 #Javascript
ES6新特性六:promise对象实例详解
Apr 21 #Javascript
You might like
Terran兵种介绍
2020/03/14 星际争霸
PHP base64+gzinflate压缩编码和解码代码
2008/10/03 PHP
通过PHP CLI实现简单的数据库实时监控调度
2009/07/01 PHP
thinkphp验证码显示不出来的解决方法
2014/03/29 PHP
PHP获取星期几的常用方法小结
2018/12/18 PHP
PHP实现15位身份证号转18位的方法分析
2019/10/16 PHP
采用CSS和JS,刚好我最近有个站点要用到下拉菜单!
2006/06/26 Javascript
用 Javascript 验证表单(form)中的单选(radio)值
2009/09/08 Javascript
用apply让javascript函数仅执行一次的代码
2010/06/27 Javascript
jQuery选择器的工作原理和优化分析
2011/07/25 Javascript
jQuery中index()方法用法实例
2014/12/27 Javascript
基于jQuery的select下拉框选择触发事件实例分析
2016/11/18 Javascript
jQuery日程管理控件glDatePicker用法详解
2017/03/29 jQuery
在ABP框架中使用BootstrapTable组件的方法
2017/07/31 Javascript
Vue.js 2.5新特性介绍(推荐)
2017/10/24 Javascript
vue.js 实现图片本地预览 裁剪 压缩 上传功能
2018/03/01 Javascript
vue form 表单提交后刷新页面的方法
2018/09/04 Javascript
vue中如何实现后台管理系统的权限控制的方法示例
2018/09/19 Javascript
nodejs简单抓包工具使用详解
2019/08/23 NodeJs
[46:20]TFT vs Secret Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
[01:07:13]TNC vs Pain 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
详解Python中的文本处理
2015/04/11 Python
python模拟点击网页按钮实现方法
2020/02/25 Python
python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例
2020/02/28 Python
Django之全局使用request.user.username的实例详解
2020/05/14 Python
如何创建一个Flask项目并进行简单配置
2020/11/18 Python
python3列表删除大量重复元素remove()方法的问题详解
2021/01/04 Python
css3让div随鼠标移动而抖动起来
2014/02/10 HTML / CSS
印尼披萨外送专家:Domino’s Pizza印尼
2017/12/28 全球购物
各营销点岗位职责范本
2014/03/05 职场文书
处级干部考察材料
2014/12/24 职场文书
建议书格式
2015/02/04 职场文书
2019个人年度目标制定攻略!
2019/07/12 职场文书
古诗文之爱国名句(77句)
2019/09/24 职场文书
Python基于Opencv识别两张相似图片
2021/04/25 Python
MySQL中B树索引和B+树索引的区别详解
2022/03/03 MySQL