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 无废话系列教程(二) jquery实战篇上
Jun 23 Javascript
从父页面读取和操作iframe中内容方法
Jul 25 Javascript
JQuery 图片延迟加载并等比缩放插件
Nov 09 Javascript
js获取系统的根路径实现介绍
Sep 08 Javascript
JavaScript获取flash对象与网上的有所不同
Apr 21 Javascript
jQuery常用操作方法及常用函数总结
Jun 19 Javascript
jquery滚动特效集锦
Jun 03 Javascript
js实现精确到毫秒的倒计时效果
Aug 05 Javascript
轻松实现jQuery添加删除按钮Click事件
Mar 13 Javascript
vue生成token保存在客户端localStorage中的方法
Oct 25 Javascript
浅析vue-router中params和query的区别
Dec 24 Javascript
JS实现秒杀倒计时特效
Jan 02 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 命名空间实例说明
2011/01/27 PHP
如何使用“PHP” 彩蛋进行敏感信息获取
2013/08/07 PHP
超棒的javascript页面顶部卷动广告效果
2007/12/01 Javascript
jquery 多行文本框(textarea)高度变化
2013/07/03 Javascript
onmouseover和onmouseout的一些问题思考
2013/08/14 Javascript
node.js中使用socket.io制作命名空间
2014/12/15 Javascript
jqueryMobile 动态添加元素,展示刷新视图的实现方法
2016/05/28 Javascript
在js中实现邮箱格式的验证方法(推荐)
2016/10/24 Javascript
常用JS图片滚动(无缝、平滑、上下左右滚动)代码大全(推荐)
2016/12/20 Javascript
angular+bootstrap的双向数据绑定实例
2017/03/03 Javascript
vue2.0实现倒计时的插件(时间戳 刷新 跳转 都不影响)
2017/03/30 Javascript
javascript实现前端分页效果
2020/06/24 Javascript
jQuery实现滑动开关效果
2020/08/02 jQuery
解决vue中使用less/sass及使用中遇到无效的问题
2020/10/24 Javascript
sqlalchemy对象转dict的示例
2014/04/22 Python
使用Python编写简单网络爬虫抓取视频下载资源
2014/11/04 Python
基于Python __dict__与dir()的区别详解
2017/10/30 Python
使用TensorFlow实现二分类的方法示例
2019/02/05 Python
python3的数据类型及数据类型转换实例详解
2019/08/20 Python
快速解决docker-py api版本不兼容的问题
2019/08/30 Python
通过实例了解Python异常处理机制底层实现
2020/07/23 Python
浅析Python 责任链设计模式
2020/09/11 Python
鲜为人知的HTML5语音合成功能
2019/05/17 HTML / CSS
英国工具中心:UK Tool Centre
2017/07/10 全球购物
Rag & Bone官网:瑞格布恩高级成衣
2018/04/19 全球购物
罗马尼亚购物网站:Vivantis.ro
2019/07/20 全球购物
莫斯科购买书籍网站:Book24
2020/01/12 全球购物
空字符串(“”)和null的区别
2012/11/13 面试题
类和结构的区别
2012/08/15 面试题
节约用水倡议书
2014/04/16 职场文书
祖国在我心中演讲稿600字
2014/09/23 职场文书
领导欢迎词致辞
2015/01/23 职场文书
2015秋季小学开学寄语
2015/05/27 职场文书
三好学生主要事迹材料
2015/11/03 职场文书
浅谈Redis主从复制以及主从复制原理
2021/05/29 Redis
Nginx HTTP跳转至HTTPS
2022/05/15 Servers