Преглед изворни кода

feat: 压缩图片到2m以下

xuqiaoying пре 3 година
родитељ
комит
fa59bdc445
2 измењених фајлова са 250 додато и 88 уклоњено
  1. 98 0
      common/compressPhoto.js
  2. 152 88
      pages2/verify/input.vue

+ 98 - 0
common/compressPhoto.js

@@ -0,0 +1,98 @@
+//通过canvas将图片压缩至指定大小
+
+//判断图片大小是否满足需求,limitSize的单位是kb
+function imageSizeIsLessLimitSize(imagePath,limitSize,lessCallback,moreCallback){
+    console.log('------imagePath,limitSize,lessCallback,moreCallback', imagePath,limitSize,lessCallback,moreCallback)
+    //获取文件信息
+    wx.getFileSystemManager().getFileInfo({
+      filePath: imagePath,
+      success:(res)=>{
+        // console.log("压缩前图片大小",res, res.size/1024,'kb');
+        if(res.size > 1024*limitSize){
+          moreCallback()
+        } else {
+          lessCallback()
+        }
+      }
+    })
+  }
+  
+  //将图片画在画布上并获取画好之后的图片的路径
+  function getCanvasImage(canvasId,imagePath,imageW,imageH,getImgSuccess){
+    //创建画布内容
+    const ctx = wx.createCanvasContext(canvasId)
+    //图片画上去,imageW和imageH是画上去的尺寸,图像和画布间隔都是0
+    ctx.drawImage(imagePath, 0, 0, imageW, imageH);
+    //这里一定要加定时器,给足够的时间去画(所以每次递归最少要耗时200ms,多次递归很耗时!)
+    ctx.draw(false, setTimeout(() => {
+      //把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径
+      wx.canvasToTempFilePath({
+        canvasId: canvasId,
+        x: 0,
+        y: 0,
+        width: imageW,
+        height: imageH,
+        quality: 1, // 取0-1,1最高质量
+        fileType: 'jpg',
+        success:(res)=>{
+          //将取出的图片路径通过回调函数返回
+          getImgSuccess(res.tempFilePath);
+        }
+      })
+    },200));
+  }
+  
+  //主函数,默认限制大小2048kb即2mb,drawWidth是绘画区域的大小
+  //初始值传入为画布自身的边长(我们这是一个正方形的画布)
+  function getLessLimitSizeImage(canvasId, imagePath, limitSize=1024, drawWidth, callback) {
+    //判断图片尺寸是否满足要求
+    imageSizeIsLessLimitSize(imagePath,limitSize,
+      (lessRes)=>{
+        //满足要求走callback,将压缩后的文件路径返回
+        console.log('满足要求走callback:', imagePath)
+        callback(imagePath);
+      },
+      (moreRes)=>{
+        //不满足要求需要压缩的时候
+        wx.getImageInfo({
+          src: imagePath,
+          success:(imageInfo)=>{
+            let maxSide = Math.max(imageInfo.width,imageInfo.height);
+            let windowW = drawWidth
+            let scale=1;
+            /*
+            这里的目的是当绘画区域缩小的比图片自身尺寸还要小的时候
+            取图片长宽的最大值,然后和当前绘画区域计算出需要放缩的比例
+            然后再画经过放缩后的尺寸,保证画出的一定是一个完整的图片。由于每次递归绘画区域都会缩小,
+            所以不用担心scale永远都是1绘画尺寸永远不变的情况,只要不满足压缩后体积的要求
+            就会缩小绘画区域,早晚会有绘画区域小于图片尺寸的情况发生
+            */
+            if(maxSide>windowW){
+              scale = windowW/maxSide
+            }
+            //trunc是去掉小数
+            let imageW = Math.trunc(imageInfo.width*scale)
+            let imageH = Math.trunc(imageInfo.height*scale)
+            // console.log('调用压缩',imageW,imageH);
+            //图片在规定绘画区域上画并获取新的图片的path
+            getCanvasImage(canvasId,imagePath,imageW,imageH,
+              (pressImgPath)=>{
+                /*
+                再去检查是否满足要求,始终缩小绘画区域,让图片适配绘画区域
+                这里乘以0.95是必须的,如果不缩小绘画区域,会出现尺寸比绘画区域小,
+                而体积比要求压缩体积大的情况出现,就会无穷递归下去,因为scale的值永远是1
+                但0.95不是固定的,你可以根据需要自己改,0到1之间,越小则绘画区域缩小的越快
+                但不建议取得太小,绘画区域缩小的太快,压出来的将总是很糊的
+                */
+                getLessLimitSizeImage(canvasId,pressImgPath,limitSize,drawWidth*0.95,callback);
+              }
+            )
+          }
+        })
+      }
+    )
+  }
+  
+  export default getLessLimitSizeImage
+  
+  

+ 152 - 88
pages2/verify/input.vue

@@ -1,5 +1,5 @@
 <template>
-  <view style="padding: 30rpx">
+  <view class="infos" style="padding: 30rpx">
     <nav-bar title="填写审核资料"></nav-bar>
     <view v-show="!agreementModal">
       <view class="topBox">
@@ -480,6 +480,16 @@
       v-model="showTableDown"
       @click="clickIndex"
     ></u-action-sheet>
+
+    <!--用于图片压缩的canvas画布,不在页面中展示,且id固定不可变 position: absolute; z-index: -1; left: -10000rpx;; top: -10000rpx;-->
+    <!-- style="width: {{cw}}px; height: {{cw}}px;" -->
+    <view class="photo_can">
+      <canvas
+        class="zip_canvas"
+        canvas-id="zipCanvas"
+      ></canvas>
+    </view>
+
   </view>
 </template>
 
@@ -487,9 +497,11 @@
 import * as baseUrls from "@/common/request.js";
 import { mapGetters, mapActions } from "vuex";
 import Handwriting from "@/common/signature.js";
+import getLessLimitSizeImage from '@/common/compressPhoto.js'
 export default {
   data() {
     return {
+      cw: wx.getSystemInfoSync().windowWidth, //画板边长默认是屏幕宽度,正方形画布
       list: [
         {
           text: "上传图片",
@@ -798,9 +810,6 @@ export default {
         );
       }
 
-      console.log(data);
-      console.log(self.copyData);
-      console.log(444);
 
       if (this.remarkStatus) {
         var arsty = {};
@@ -905,8 +914,7 @@ export default {
                 this.apply_post_disabled = true;
               }
             }
-
-            if (this.userInfo.companyName) {
+            if (this.userInfo && this.userInfo.companyName) {
               this.$set(this.form, "work_unit", this.userInfo.companyName);
             }
             resolve();
@@ -914,28 +922,39 @@ export default {
       });
     },
     uploadImgs() {
-      var self = this;
       uni.chooseImage({
         count: 1, //默认9
         sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
-        success: function (res) {
+        success: (res) => {
           if (res.tempFiles[0].size > 2097152) {
-            self.$method.showToast("上传图片不得大于2M");
+            // this.$method.showToast("上传图片不得大于2M");
+            // 需要压缩
+            let canvasId = 'zipCanvas'
+            let imagePath = res.tempFiles[0].path //原图的路径
+            let limitSize = 2048 //大小限制2048kb
+            let drawWidth = wx.getSystemInfoSync().windowWidth //初始绘画区域是画布自身的宽度也就是屏幕宽度
+            getLessLimitSizeImage(canvasId, imagePath, limitSize, drawWidth, async (resPath)=>{
+              //resPath就是压缩后图片的路径
+              this.uploadImgsChild(resPath)
+            })
             return;
           } else {
-            var type = res.tempFiles[0].path.split(".").splice(-1);
-            if (type[0] != "jpg" && type[0] != "png" && type[0] != "jpeg") {
-              self.$method.showToast("请上传图片格式");
-              return;
-            }
-            self.$set(self.form, "commitment_seal", res.tempFiles[0].path);
-            self.$nextTick(function () {
-              this.resultForm();
-            });
+            this.uploadImgsChild(res.tempFiles[0].path)
           }
         },
       });
     },
+    uploadImgsChild(path) {
+      var type = path.split(".").splice(-1)
+      if (type[0] != "jpg" && type[0] != "png" && type[0] != "jpeg") {
+        this.$method.showToast("请上传图片格式")
+        return
+      }
+      this.$set(this.form, "commitment_seal", path)
+      this.$nextTick(() => {
+        this.resultForm()
+      });
+    },
     uploadFieds() {
       var self = this;
       wx.chooseMessageFile({
@@ -1431,33 +1450,39 @@ export default {
       });
     },
     async changePhotoListHeader1(lists, name) {
-      console.log('个人近照---',lists);
       if (lists.length) {
         this.fileList1 = lists;
-        console.log(lists, "lists1");
+        // console.log(lists, "lists1");
         if (
           lists[0].url.indexOf("//tmp") !== -1 ||
           lists[0].url.indexOf("//temp") !== -1
         ) {
-          console.log('----')
-          this.$set(
-            this.form,
-            "recent_photos",
-            await this.$method.imageInfos(lists[0].url)
-          );
+          if (lists[0].file.size < 2 * 1024 * 1024) {
+            // 以前的
+            this.$set(this.form, "recent_photos", await this.$method.imageInfos(lists[0].url))
+          } else {
+            // 需要压缩
+            let canvasId = 'zipCanvas'
+            let imagePath = lists[0].url; //原图的路径
+            let limitSize = 2048; //大小限制2048kb
+            let drawWidth = wx.getSystemInfoSync().windowWidth //初始绘画区域是画布自身的宽度也就是屏幕宽度
+            getLessLimitSizeImage(canvasId, imagePath, limitSize, drawWidth, async (resPath)=>{
+              //resPath就是压缩后图片的路径
+              this.$set(this.form, "recent_photos", await this.$method.imageInfos(resPath))
+            })
+          }
         }
       } else {
         this.fileList1 = [];
         this.$set(this.form, "recent_photos", "");
-        console.log(3, this.form.recent_photos);
       }
       this.openVerify = false;
       this.$nextTick(function () {
-        console.log(4);
         this.resultForm();
       });
     },
     async changePhotoListHeader2(lists, name) {
+      // console.log('身份证照片zhengmian:', lists, this.$refs.idcard_face_photo)
       if (lists.length) {
         this.fileList2 = lists;
         if (
@@ -1465,39 +1490,56 @@ export default {
           lists[0].url.indexOf("//temp") !== -1
         ) {
           let url = lists[0].url;
+          let size = lists[0].file.size
           this.$refs.idcard_face_photo[0].remove(0);
 
-          uni.compressImage({
-            src: url,
-            quality: 75,
-            width: "50%",
-            height: "50%",
-            success: async (rest) => {
-              let res = await this.faceCertificationIDCardOCR(
-                1,
-                rest.tempFilePath
-              );
+          // console.log('url', url, size)
+          let titleMsg = '请上传正确清晰的身份证人像面照片'
+          if (size < 2 * 1024 * 1024) {
+            this.checkIdCard(1, url, titleMsg, 'idcard_face_photo')
+          } else {
+            // 需要压缩
+            let canvasId = 'zipCanvas'
+            let imagePath = url //原图的路径
+            let limitSize = 2048 //大小限制2048kb
+            let drawWidth = wx.getSystemInfoSync().windowWidth //初始绘画区域是画布自身的宽度也就是屏幕宽度
+            getLessLimitSizeImage(canvasId, imagePath, limitSize, drawWidth, async (resPath)=>{
+              //resPath就是压缩后图片的路径
+              this.checkIdCard(1, resPath, titleMsg, 'idcard_face_photo')
+            })
+          }
 
-              if (res.data.code == 500) {
-                uni.showToast({
-                  icon: "none",
-                  title: "请上传正确清晰的身份证人像面照片",
-                });
-                return;
-              }
-              this.$refs.idcard_face_photo[0].lists = [
-                {
-                  url: this.$method.splitImgHost(res.data.data.IdImgPath),
-                },
-              ];
-              this.$set(
-                this.form,
-                "idcard_face_photo",
-                res.data.data.IdImgPath
-              );
-              console.log(this.form, "idcard_face_photo");
-            },
-          });
+          // uni.compressImage({
+          //   src: url,
+          //   quality: 75,
+          //   width: "50%",
+          //   height: "50%",
+          //   success: async (rest) => {
+          //     let res = await this.faceCertificationIDCardOCR(
+          //       1,
+          //       rest.tempFilePath
+          //     );
+
+          //     if (res.data.code == 500) {
+          //       uni.showToast({
+          //         icon: "none",
+          //         title: "请上传正确清晰的身份证人像面照片",
+          //       });
+          //       return;
+          //     }
+          //     this.$refs.idcard_face_photo[0].lists = [
+          //       {
+          //         url: this.$method.splitImgHost(res.data.data.IdImgPath),
+          //       },
+          //     ];
+          //     this.$set(
+          //       this.form,
+          //       "idcard_face_photo",
+          //       res.data.data.IdImgPath
+          //     );
+          //     console.log(this.form, "idcard_face_photo");
+          //   },
+          // });
         }
       } else {
         this.fileList2 = [];
@@ -1517,37 +1559,23 @@ export default {
         ) {
           console.log("//tem");
           let url = lists[0].url;
+          let size = lists[0].file.size
           this.$refs.idcard_national_photo[0].remove(0);
-          uni.compressImage({
-            src: url,
-            quality: 75,
-            width: "50%",
-            height: "50%",
-            success: async (rest) => {
-              let res = await this.faceCertificationIDCardOCR(
-                2,
-                rest.tempFilePath
-              );
-              if (res.data.code == 500) {
-                uni.showToast({
-                  icon: "none",
-                  title: "请上传正确清晰的身份证国徽面照片",
-                });
-                return;
-              }
-              this.$refs.idcard_national_photo[0].lists = [
-                {
-                  url: this.$method.splitImgHost(res.data.data.IdImgPath),
-                },
-              ];
-              this.$set(
-                this.form,
-                "idcard_national_photo",
-                res.data.data.IdImgPath
-              );
-              console.log(this.form, "idcard_national_photo");
-            },
-          });
+
+          let titleMsg = '请上传正确清晰的身份证国徽面照片'
+          if (size < 2 * 1024 * 1024) {
+            this.checkIdCard(2, url, titleMsg, 'idcard_national_photo')
+          } else {
+            // 需要压缩
+            let canvasId = 'zipCanvas'
+            let imagePath = url //原图的路径
+            let limitSize = 2048 //大小限制2048kb
+            let drawWidth = wx.getSystemInfoSync().windowWidth //初始绘画区域是画布自身的宽度也就是屏幕宽度
+            getLessLimitSizeImage(canvasId, imagePath, limitSize, drawWidth, async (resPath)=>{
+              //resPath就是压缩后图片的路径
+              this.checkIdCard(2, resPath, titleMsg, 'idcard_national_photo')
+            })
+          }
         }
       } else {
         this.fileList3 = [];
@@ -1558,6 +1586,24 @@ export default {
         this.resultForm();
       });
     },
+    async checkIdCard(cardSide, url, titleMsg, paramType) {
+      let res = await this.faceCertificationIDCardOCR(cardSide, url);
+
+      if (res.data.code == 500) {
+        uni.showToast({
+          icon: "none",
+          title: titleMsg,
+        });
+        return;
+      }
+      this.$refs[paramType][0].lists = [
+        {
+          url: this.$method.splitImgHost(res.data.data.IdImgPath),
+        },
+      ];
+      this.$set(this.form, paramType, res.data.data.IdImgPath);
+      // console.log(this.form[paramType], '《===',paramType);
+    },
     getTimes(key) {
       if (this.form[key]) {
         return this.form[key];
@@ -1900,6 +1946,24 @@ page {
 }
 </style>
 <style scope lang="scss">
+.infos {
+  position: relative;
+  top: 0rpx;
+  left: 0rpx;
+  .photo_can {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    z-index: -1; 
+    left: -10000rpx;
+    top: -10000rpx;
+  }
+  .zip_canvas {
+    width: 100%;
+    height: 600rpx;
+    border: 2rpx solid #333;
+  }
+}
 .ctoples {
   position: absolute;
   top: 0;