前端压缩图片问题vue+vant+cavans

上一篇写到压缩图片的相关代码,后面开发中还有一些bug

例如无法同时上传多张图片,这里需要遍历压缩,还有压缩png图片背景黑色的问题解决 我调整了部分代码

  <van-uploader :max-count="9"  :after-read="afterReadImg"   @delete="onDelete"
      v-model="fileList" @click-upload="setBannerMax"  multiple>
      <div class="upload flex flex-col" v-if="fileList.length < 9">
        <img class="add-img" src="@/assets/images/add_img.png" />
        <span v-if="!fileList.length">拍照上传</span>
        <span v-else>{{ fileList.length }}/9</span>
      </div>
    </van-uploader>

因为异步获取图片问题我这边把before-read方法去掉了,调取压缩放在了after-read方法里面

   // 上传图片
   async  afterReadImg(file) {
      let num = ''; 
      for (let i = 0; i < 13; i++) { num += Math.floor(Math.random() * 10); }
      //上传一张图片或拍照 
      if(!file.length){
          file.status = 'uploading'
          file.message = '上传中...'
          this.blobToBase64(file.file).then(result=>{
          //加水印
          //  this.addwater(file)
        // this.$nextTick(()=>{
   fileupload(result,this.form.service_id,num,this.address).then(res => {
        if (res.status === 's') {
          // this.form.banner = res.imgUrl
          this.imgList.push({
            url:res.imgUrl,
            id: file.lastModified
          })
          this.changeImgString()
          file.status = 'done'
          file.message = '上传完成'
        } else {
          setTimeout(() => {
            file.status = 'failed'
            file.message = '上传失败'
          }, 1000)
        }
      })
    })
    // })
  }else{
 //上传多张图片
    file.forEach(item=>{
      item.status='uploading'
    item.message = '上传中...'
  this.blobToBase64(item.file).then(result=>{
       fileupload(result,this.form.service_id,num,this.address).then(res => {
        if (res.status === 's') {
          this.imgList.push({
            url:res.imgUrl,
            id: item.file.lastModified
          })
        this.changeImgString()
        setTimeout(() => {
          item.status = 'done'
          item.message = '上传完成'
          }, 1000)
        } else {
          setTimeout(() => {
            item.status = 'failed'
            item.message = '上传失败'
          }, 1000)
        }
      })
  })
    })
    }

 
    }

这边是我根据项目需求添加了部分别的代码,可根据实际调整修改

将获取到的二进制文件 转 base64文件

 async blobToBase64 (blob) {
      const self = await this // 绑定this
      const reader = await new FileReader() // 实例化一个reader文件
      await reader.readAsDataURL(blob) // 添加二进制文件
      return new Promise(function (resolve, reject) {
        reader.onload = async function (event) {
          const base64 = await event.target.result // 获取到它的base64文件
          const scale = 0.70 // 设置缩放比例 (0-1)
          let file = await self.compressImg(base64, scale)
          resolve(file)
        }
      })
    },

调用压缩图片方法

 async compressImg (base64, scale) {
      console.log(`执行缩放程序,scale=${scale}`)
      // 处理缩放,转换格式
      // 下面的注释就不写了,就是new 一个图片,用canvas来压缩
      const img = new Image()
      img.src = base64
      return new Promise(function (resolve, reject) {
        img.onload = async function () {
          const canvas = document.createElement('canvas')
          const ctx = canvas.getContext('2d')
          canvas.setAttribute('width', this.width)
          canvas.setAttribute('height', this.height)
          // 在canvas绘制前填充白色背景  解决出现压缩png图片背景黑色问题
          ctx.fillStyle = "#fff";
          ctx.clearRect(0, 0, canvas.width, canvas.height)
          ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
          // 转成base64 文件
          base64 = canvas.toDataURL('image/jpeg', 0.3)
          const arr = base64.split(',')
          const mime = arr[0].match(/:(.*?);/)[1]
          const bytes = atob(arr[1])
          const bytesLength = bytes.length
          const u8arr = new Uint8Array(bytesLength)
          for (let i = 0; i < bytes.length; i++) {
            u8arr[i] = bytes.charCodeAt(i)
          }
          const file = await new File([u8arr], 'filename', { type: mime })
          resolve(file)
        }
      })
    },

开发过程中发现某些png格式图片透明背景压缩后会变成黑色

其实问题就出现在canvas转base64的方法上,不指定类型的话默认是使用image/jpeg格式转的,但是jpeg格式不能没有底色, 所以默认会填充黑色,如下图

 详图如下

canvas.toDataURL(type, quality);

这个quality参数是指定清晰度的,只支持jpeg格式,不支持png,png设置了没用

既然透明图片会出现黑底,那么我们压缩前通过canvas把图片底色变成 白色不就可以了吗

有两种思路,一种是通过读取图片数据,设置透明的部分颜色成白色,一种是直接将canvas画一层白色底色再绘画图片

第一种:
这个我没有封装,需要的自行封装

// 将canvas的透明背景设置成白色
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
for(var i = 0; i < imageData.data.length; i += 4) {
    // 当该像素是透明的,则设置成白色
    if(imageData.data[i + 3] == 0) {
        imageData.data[i] = 255;
        imageData.data[i + 1] = 255;
        imageData.data[i + 2] = 255;
        imageData.data[i + 3] = 255; 
    }
}
context.putImageData(imageData, 0, 0);

第二种:我现在用这个方式
关键代码:

  // 在canvas绘制前填充白色背景
            context.fillStyle = "#fff";
            context.fillRect(0, 0, canvas.width, canvas.height);

总结

以上是我压缩图片所用的所有方法和bug解决,代码还有许多可以优化,我一小白只能写到这个程度了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Doraemen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值