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 相关文章推荐
神奇的7个jQuery 3D插件整理
Jan 06 Javascript
jquerydom对象的事件隐藏显示和对象数组示例
Dec 10 Javascript
解析jquery中的ajax缓存问题
Dec 19 Javascript
js 通过cookie实现刷新不变化树形菜单
Oct 30 Javascript
Javascript实现苹果悬浮虚拟按钮
Apr 10 Javascript
详解jQuery事件
Jan 13 Javascript
JS实现异步上传压缩图片
Apr 22 Javascript
关于Vue项目跨平台运行问题的解决方法
Sep 18 Javascript
三种Webpack打包方式(小结)
Sep 19 Javascript
微信小程序http连接访问解决方案的示例
Nov 05 Javascript
使用react context 实现vue插槽slot功能
Jul 18 Javascript
解决三元运算符 报错“SyntaxError: can''t assign to conditional expression”
Feb 12 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
PHP开发框架kohana中处理ajax请求的例子
2014/07/14 PHP
PHP设计模式之工厂模式实例总结
2017/09/01 PHP
laravel框架 api自定义全局异常处理方法
2019/10/11 PHP
使一个函数作为另外一个函数的参数来运行的javascript代码
2007/08/13 Javascript
js树形控件脚本代码
2008/07/24 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之三
2012/01/03 Javascript
DWR实现模拟Google搜索效果实现原理及代码
2013/01/30 Javascript
jQuery回车实现登录简单实现
2013/08/20 Javascript
extjs render 用法介绍
2013/09/11 Javascript
js中通过split函数分割字符串成数组小例子
2013/09/21 Javascript
Google Dart编程语法和基本类型学习教程
2013/11/27 Javascript
javascript内置对象arguments详解
2014/03/16 Javascript
jQuery.holdReady()方法用法实例
2014/12/27 Javascript
js实现仿MSN带关闭功能的右下角弹窗代码
2015/09/04 Javascript
Jquery使用小技巧汇总
2015/12/29 Javascript
基于Bootstrap漂亮简洁的CSS3价格表(附源码下载)
2017/02/28 Javascript
Angularjs在360兼容模式下取数据缓存问题的解决办法
2017/06/22 Javascript
Vue 多层组件嵌套二种实现方式(测试实例)
2017/09/08 Javascript
微信小程序实现tab和swiper切换结合效果
2020/07/17 Javascript
vue组件中使用props传递数据的实例详解
2018/04/08 Javascript
如何基于JS截获动态代码
2019/12/25 Javascript
python3使用SMTP发送简单文本邮件
2018/06/19 Python
Python利用Scrapy框架爬取豆瓣电影示例
2020/01/17 Python
TripAdvisor西班牙官方网站:全球领先的旅游网站
2018/01/10 全球购物
生产管理的三大手法
2013/11/11 职场文书
路政管理专业推荐信
2013/11/11 职场文书
工业自动化毕业生自荐信范文
2014/01/04 职场文书
关于青春的演讲稿三分钟
2014/08/22 职场文书
村党支部对照检查材料思想汇报
2014/09/28 职场文书
2015年幼儿园新年寄语
2014/12/08 职场文书
2015年销售助理工作总结
2015/05/11 职场文书
小学见习报告
2015/06/23 职场文书
麦田里的守望者读书笔记
2015/06/30 职场文书
入党申请书怎么写?
2019/06/21 职场文书
使用@Value值注入及配置文件组件扫描
2021/07/09 Java/Android
golang实现一个简单的websocket聊天室功能
2021/10/05 Golang