JavaScript使用H5 FileReader和Image对象获取本地图片的分辨率

业务场景

试想这样的应用场景:

当我们上传本地图片时,需要校验图片的分辨率,只有水平分辨率不大于1920、垂直分辨率不大于1080的图片才允许上传。

后端处理方案

显然,我们是可以将分辨率校验交给后端的,这样的问题在于,后端校验需要前端先发起ajax请求,并且后端校验也需要一定的处理时间,就整体体验而言,用户等待时间较长,不利于用户体验。

因此还是推荐前端校验,直接给出结果。

难点所在

对于type='file'的input框,在其change事件中,我们可以直接拿到file对象,包含了name、size等属性,但是并不包含分辨率数据。因为这时,图片尚未渲染到dom中,浏览器不知道这是一个图片,拿不到分辨率也可以理解。如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <input type="file" accept="image/jpg,image/jpeg,image/png" id="fileInput" />
    <script>
      document
        .getElementById("fileInput")
        .addEventListener("change", handleFileChange, false);
      function handleFileChange(e) {
     
     
        console.log(e.target.files[0]);
      }
    </script>
  </body>
</html>

在这里插入图片描述

破局:使用FileReader转换为base64格式

虽然原生的file对象拿不到图片的分辨率信息,但是借助于FileReader则可以读取到文件的内部数据,并转换为base64。

      function handleFileChange(e) {
    
    
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function () {
    
    
          if (reader.readyState == 2) {
    
    
            console.log(reader.result);
          }
        };
      }

在这里插入图片描述

突破:使用Image对象获取分辨率

现在,已经拿到base64数据,那么只需要创建一个Image实例,并将其src 设置为base64数据地址,再监听onload事件就可以拿到分辨率了,如下:

      function handleFileChange(e) {
    
    
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function () {
    
    
          if (reader.readyState == 2) {
    
    
            const img = new Image();
            img.src = reader.result;
            img.onload = function () {
    
    
              console.log(this.height, this.width);
            };
          }
        };
      }

在这里插入图片描述

时序:使用promise解决异步和同步问题

以上,我们虽然能够拿到数据,但是,获取分辨率的过程是异步的,例如我们监听了reader.onload、img.onload事件。显然,我们校验突破分辨率时,需要等待这些过程执行完,才能给出结果。而对于图片的校验很可能是同时还需要校验格式、文件大小,这些都被封装在校验函数中,而我们的校验分辨率的函数则应属于整个校验过程的一部分
即,整个校验函数中需要等待校验分辨率函数的结果,这是一个同步的过程
这并不困难,我们只需要使用es6的promise即可比较容易的达成这一目标,写法多样,下面提供一种示例:

function validRatio(file) {
    
    
      return new Promise(resolve => {
    
    
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function() {
    
    
          if (reader.readyState == 2) {
    
    
            const img = new Image();
            img.src = reader.result;
            img.onload = function() {
    
    
              const bool = this.height > 1080 || this.width > 1920;
              if (bool) {
    
    
                resolve(false);
              }
              resolve(true);
            };
          }
        };
      });
    },
    async function validateFile(file) {
    
    
      //...
      const isRatioValid = await validRatio(file);
      //...
  }

如有其他更好的方案,欢迎指出!

全文完。

猜你喜欢

转载自blog.csdn.net/u012443286/article/details/106146368