利用canvas进行的图片压缩

涉及到手机拍照上传,因为有些照片比较大,影响客户体验,所以需要对照片进行压缩,简述一下压缩的原理就是利用canvas把图片重绘一遍,按照一定的质量比例。

这里贴上代码记录一下,方便以后使用

如果图片名字为image.jpg会串图,所以需要单独处理一下名字为image.jpg的图片。

js部分

// 图片获取
   private upload(event: any) {
     this.form['快照'] = [];
     event.target.files.forEach((v: any, i: number) => {
       this.preview(v, i);
     });
   }
  private preview(file: any, index: number) {
      const reader = new FileReader();
      const img = document.createElement('img');
      img.id = `img${index}`;
      img.className = 'hide';
      document.body.appendChild(img);
      const img_original: any = document.getElementById(`img${index}`);
      reader.onload = (e: any) => {
          img_original.src = e.target.result;// 这里的result是一个blob格式的数据,因为是多张上传所以用了这种写法,单张可以写成this.result,外层循环也可以去掉。
          img_original.onload = () => {
              console.log('图片原始宽高:', img_original.naturalWidth, img_original.naturalHeight);
              console.log('图片原始大小:', file.size);
          };
      };
      reader.readAsDataURL(file);
      setTimeout(() => {
        this.compress(file, index);
      }, 1000);// 此处作为一个异步处理,因为图片越大压缩时间越久,所以如果出现压缩失败,或者图片显示失败可以把时间调长一些。
  }
  // 图片压缩
  private compress(file: any, index: number) {
    let blob;
    const document: any = window.document;
    // 压缩到图片原始宽高的一半
    const img_original = document.getElementById(`img${index}`);
    const w = img_original.naturalWidth / 2;
    const h = img_original.naturalHeight / 2;
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const anw = document.createAttribute('width');
    anw.nodeValue = w;
    const anh = document.createAttribute('height');
    anh.nodeValue = h;
    canvas.setAttributeNode(anw);
    canvas.setAttributeNode(anh);
    ctx.fillRect(0, 0, w, h);
    ctx.drawImage(img_original, 0, 0, w, h);

    const base64 = canvas.toDataURL('image/jpeg', 0.4); // 压缩后质量
    const bytes = window.atob(base64.split(',')[1]);
    const ab = new ArrayBuffer(bytes.length);
    const ia = new Uint8Array(ab);
    for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
    }
    blob = new Blob([ab], {type: 'image/jpeg'});
    this.imgFormat(blob, file);
    console.log('压缩后的图片大小', blob.size);
  }

h5部分

  <img v-for="(item, index) in form['快照']" :key="index" :src="item" class="imgShow"/>
                  <!-- </div> -->
                <div class="upload">
                  <img src="images/icon_add.png" />
                  <input class="file" type="file" @change="upload" accept=".jpg, .jpeg, .webp, .png, .bmp" multiple="multiple"/>
                </div>

blob数据类型一般是二进制存储图像,音频等内容,可以直接在src后面跟上blob来显示对应的图像,音频想来也可以,不过目前并没有用到。

所以一个新的发现就是:src后面不一定要跟地址,blob数据也可以显示对应的内容。

 

posted @ 2022-02-08 16:05  妄欢  阅读(484)  评论(0编辑  收藏  举报