前端图片压缩基于(h5 file API & canvas)

前端压缩的意义

 

对于大尺寸图片的上传, 如头像等, 在前端进行压缩除了省流量外,最大的意义是提高了上传速度, 改善了用户体验。

以下例子可作为一个头像上传压缩, 图片被压缩至长宽最大小于200px。

实现原理

核心API使用canvasdrawImage()方法。

canvasdrawImage()方法API如下:

context.drawImage(img, dx, dy);
context.drawImage(img, dx, dy, dWidth, dHeight);
context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

原理代码如下

var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 200;
// 核心JS就这个
context.drawImage(img,0,0,200,200);

图片呈现在浏览器

HTML5 file API可以让图片在上传之前直接在浏览器中显示,通常使用FileReader方法,代码示意如下:

var reader = new FileReader(), img = new Image();
// 读文件成功的回调
reader.onload = function(e) {
  // e.target.result就是图片的base64地址信息
  img.src = e.target.result;
};
eleFile.addEventListener('change', function (event) {
    reader.readAsDataURL(event.target.files[0]);
});

于是,包含图片信息的context.drawImage()方法中的img图片就有了。

把canvas画布转换成img图像

canvas.toDataURL()方法
语法如下:

canvas.toDataURL(mimeType, qualityArgument)

可以把图片转换成base64格式信息,纯字符的图片表示法。

canvas.toBlob()方法语法如下:

canvas.toBlob(callback, mimeType, qualityArgument)

可以把canvas转换成Blob文件,通常用在文件上传中,因为是二进制的,对后端更加友好。

 

完整代码如下:

<!doctype html>
<html>

<head>
  <title>前端压缩</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

</head>

<body>
  <input id="file" type="file">
  <img id="img">
  <script type="text/javascript">
    var eleFile = document.querySelector('#file');

    // 压缩图片需要的一些元素和对象
    var reader = new FileReader(),
      img = new Image();

    // 选择的文件对象
    var file = null;

    // 缩放图片需要的canvas
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');

    // base64地址图片加载完毕后
    img.onload = function() {
      // 图片原始尺寸
      var originWidth = this.width;
      var originHeight = this.height;
      // 最大尺寸限制
      var maxWidth = 200,
        maxHeight = 200;
      // 目标尺寸
      var targetWidth = originWidth,
        targetHeight = originHeight;
      // 图片尺寸超过400x400的限制
      if (originWidth > maxWidth || originHeight > maxHeight) {
        if (originWidth / originHeight > maxWidth / maxHeight) {
          // 更宽,按照宽度限定尺寸
          targetWidth = maxWidth;
          targetHeight = Math.round(maxWidth * (originHeight / originWidth));
        } else {
          targetHeight = maxHeight;
          targetWidth = Math.round(maxHeight * (originWidth / originHeight));
        }
      }

      // canvas对图片进行缩放
      canvas.width = targetWidth;
      canvas.height = targetHeight;
      // 清除画布
      context.clearRect(0, 0, targetWidth, targetHeight);
      // 图片压缩
      context.drawImage(img, 0, 0, targetWidth, targetHeight);
      // canvas转为blob并上传
      canvas.toBlob(function(blob) {

        var eleLink = document.createElement('a');
        eleLink.download = '压缩';
        eleLink.style.display = 'none';
        eleLink.href = URL.createObjectURL(blob);

        document.getElementById('img').src = eleLink.href;
        // 触发点击
        document.body.appendChild(eleLink);
        eleLink.click();
        // 然后移除
        // document.body.removeChild(eleLink);

      }, file.type || 'image/png');
    };

    // 文件base64化,以便获知图片原始尺寸
    reader.onload = function(e) {
      img.src = e.target.result;
    };
    eleFile.addEventListener('change', function(event) {
      file = event.target.files[0];
      // 选择的文件是图片
      if (file.type.indexOf('image') == 0) {
        reader.readAsDataURL(file);
      }
    });
  </script>

</body>

</html>

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注