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 相关文章推荐
js null undefined 空区别说明
Jun 13 Javascript
javascript中的继承实例代码
Apr 27 Javascript
关于使用 jBox 对话框的提交不能弹出问题解决方法
Nov 07 Javascript
JavaScript实现基于十进制的四舍五入实例
Jul 17 Javascript
浅谈JavaScript 的执行顺序
Aug 07 Javascript
jQuery实现的背景动态变化导航菜单效果
Aug 24 Javascript
js如何判断是否在iframe中及防止网页被别站用iframe嵌套
Jan 11 Javascript
AngularJS入门教程一:路由用法初探
May 27 Javascript
bootstrap精简教程_动力节点Java学院整理
Jul 14 Javascript
详解angular2.x创建项目入门指令
Oct 11 Javascript
中高级前端必须了解的JS中的内存管理(推荐)
Jul 04 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
Feb 15 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使用MySQL保存session会话的方法
2015/06/18 PHP
基于Laravel实现的用户动态模块开发
2017/09/21 PHP
PHP的mysqli_rollback()函数讲解
2019/01/23 PHP
PHP如何开启Opcache功能提升程序处理效率
2020/04/27 PHP
JavaScript省市联动实现代码
2014/02/15 Javascript
jQuery的animate函数实现图文切换动画效果
2015/05/03 Javascript
jQuery实现带滚动导航效果的全屏滚动相册实例
2015/06/19 Javascript
jquery自定义右键菜单、全选、不连续选择
2016/03/01 Javascript
使用HTML5+Boostrap打造简单的音乐播放器
2016/08/05 Javascript
jQuery中绑定事件bind() on() live() one()的异同
2017/02/23 Javascript
详解axios在node.js中的post使用
2017/04/27 Javascript
JavaScript实现时间表动态效果
2017/07/15 Javascript
详解基于Vue2.0实现的移动端弹窗(Alert, Confirm, Toast)组件
2018/08/02 Javascript
layui 对弹窗 form表单赋值的实现方法
2019/09/04 Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
2020/02/14 Javascript
解决Vue大括号字符换行踩的坑
2020/11/09 Javascript
微信小程序实现电影App导航和轮播
2020/11/30 Javascript
深入讲解Python中的迭代器和生成器
2015/10/26 Python
Python脚本获取操作系统版本信息
2016/12/17 Python
python:print格式化输出到文件的实例
2018/05/14 Python
python实现将读入的多维list转为一维list的方法
2018/06/28 Python
Python实现基于PIL和tesseract的验证码识别功能示例
2018/07/11 Python
详解python运行三种方式
2019/05/13 Python
Python爬虫抓取技术的一些经验
2019/07/12 Python
python按键按住不放持续响应的实例代码
2019/07/17 Python
Python3使用PySynth制作音乐的方法
2019/09/09 Python
详解Django配置优化方法
2019/11/18 Python
Python之——生成动态路由轨迹图的实例
2019/11/22 Python
PyTorch 随机数生成占用 CPU 过高的解决方法
2020/01/13 Python
pytorch:model.train和model.eval用法及区别详解
2020/02/20 Python
Python中内建模块collections如何使用
2020/05/27 Python
Python extract及contains方法代码实例
2020/09/11 Python
世界上最好的足球商店:Unisport
2019/03/02 全球购物
高中打架检讨书
2014/02/13 职场文书
酒店秘书求职信范文
2014/02/17 职场文书
开发微信小程序之WXSS样式教程
2022/04/18 HTML / CSS