angularjs之手机端input图片上传(续)

为啥要写个续呢?解决一个问题:图片压缩

BTW,本文是针对ajax提交,如果本身就是form表单提交就不需要看了。

上一篇里说到h5可以用FileReader获取到图片信息,如base64,按道理这就可以传给服务端了,但是当图片很大的时候,这个字符串可能会写满好几张a4纸,这显然不合适,再者字符串太大服务端也接受不到- -于是发送之前压缩一下是个不错的选择,上代码:

 var zipPic=function (result) {
      var canvas=document.getElementById("uploadImg");
      var cxt=canvas.getContext('2d');
      var img=new Image();
      img.src= result;
      canvas.width=640;
      canvas.height=640*(img.height/img.width);
      cxt.drawImage(img,0,0,640,canvas.height);
      return canvas.toDataURL("image/jpeg",0.9);
 }

cxt.drawImage会将result所代表的图片绘制到canvas上去,并且重新指定了图片的宽高,
drawImage有3个方法:
在画布上定位图像:
context.drawImage(img,x,y);
在画布上定位图像,并规定图像的宽度和高度:
context.drawImage(img,x,y,width,height);
剪切图像,并在画布上定位被剪切的部分:
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
具体参数意思可以到w3school去看。

canvas.toDataURL就是压缩过后的base64,第一个参数是格式,有的时候传的图片时png什么的都可以转成jpg,第二个参数可以理解为画面质量,0~1,很好理解。

ok,到此为止,一切都很美好,然而……
以上方法在Android上都运行正常,然后在ios上toDataURL取到的却是空,百度之,发现ios自带canvas坑(以下摘自http://www.cnblogs.com/zhwl/p/4961473.html):
首先是图片的大小,如果图片的大小超过两百万像素,图片也是无法绘制到canvas上的,调用drawImage的时候不会报错,但是你用toDataURL获取图片数据的时候获取到的是空的图片数据。
再者就是canvas的大小有限制,如果canvas的大小大于大概五百万像素(即宽高乘积)的时候,不仅图片画不出来,其他什么东西也都是画不出来的。

应对第一种限制,处理办法就是瓦片绘制了。瓦片绘制,也就是将图片分割成多块绘制到canvas上,我代码里的做法是把图片分割成100万像素一块的大小,再绘制到canvas上。
应对第二种限制,我的处理办法是对图片的宽高进行适当压缩,我代码里为了保险起见,设的上限是四百万像素,如果图片大于四百万像素就压缩到小于四百万像素。四百万像素的图片应该够了,算起来宽高都有2000X2000了。

定义两个canvas:

    var canvas = document.createElement("canvas");
    var ctx=canvas.getContext('2d');
    var tCanvas = document.createElement("canvas");
    var tctx = tCanvas.getContext("2d");代码片

压缩方法:

    //使用canvas对大图片进行压缩
    function compress(img) {
      var width = img.width;
      var height = img.height;
      //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
      var ratio;
      if ((ratio = width * height / 4000000) > 1) {
        ratio = Math.sqrt(ratio);
        width /= ratio;
        height /= ratio;
      } else {
        ratio = 1;
      }
      canvas.width = width;
      canvas.height = height;
      // 铺底色
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      //如果图片像素大于100万则使用瓦片绘制
      var count;
      if ((count = width * height / 1000000) > 1) {
        count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片
      // 计算每块瓦片的宽和高
        var nw = ~~(width / count);
        var nh = ~~(height / count);
        tCanvas.width = nw;
        tCanvas.height = nh;
        for (var i = 0; i < count; i++) {
          for (var j = 0; j < count; j++) {
            tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
            ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
          }
        }
      } else {
        ctx.drawImage(img, 0, 0, width, height);
      }
      //进行最小压缩
      var ndata = canvas.toDataURL('image/jpeg', 0.1);
      // console.log('压缩前:' + initSize);
      // console.log('压缩后:' + ndata.length);
      // console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");
      tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
      return ndata;
    }

压缩方法有了,还要注意一点就是调用的时候,我当时在这花了蛮久时间0.0

reader.onload = function (e) {
            var result=this.result;
            $scope.success.up = true;
            var img=new Image();
            img.src= result;

            var maxsize = 100 * 1024;
            if(result.length<=maxsize){
              transferImgSrc=result;
            }else {
              if(img.complete){//一定要等图片加载完了再调压缩
                callback();
              }else {
                img.onload=callback;
              }
              function callback() {
                transferImgSrc = compress(img);//此处得到base64
                img = null;
              }
            }
 }

猜你喜欢

转载自blog.csdn.net/leebin_20/article/details/53322886