前端压缩图片,以及使用(iview,element-ui )的upload 组件上传前压缩

8 篇文章 0 订阅
4 篇文章 0 订阅

前端压缩图片,以及使用(iview,element-ui )的upload 组件上传前压缩


前言

  今天分享一下前端如何压缩图片。


一、压缩方法介绍

前端压缩图片,主要是使用了 toDataURL 这个canvas 的方法,其实就是把 canvas 画布上的内容获取到。

这个方法有两个参数,MDN 解释是

参数
type 可选  图片格式,默认为 image/png
encoderOptions 可选
  在指定图片格式为 image/jpegimage/webp 的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。

也就是压缩图片只支持上面两种格式(压缩后的格式)
其他格式自行尝试(博主测过png,还压大了。。)

此方法返回一个base64 的图片数据

在上传中使用的是File或者Blob格式的数据,因此还需要处理base64的数据


二、压缩代码

js 方法

    // 图片base64数据获取
	const photoCompress = (file, compressedOption, callback) => {
      let fileReader = new FileReader()
      fileReader.readAsDataURL(file)

      fileReader.onload = () => {
        let fileResult = fileReader.result
        canvasDataURL(fileResult, compressedOption, callback)
      }
    }

	// 图片渲染至画布 并获取指定质量图片
    const canvasDataURL = (path, compressedOption, callback) => {
      let img = new Image()
      img.src = path
      img.onload = () => {
        // 设置压缩后图片规格
        let quality = compressedOption.quality
        let w = compressedOption.width || img.width

        // 判断只存在宽度时,根据比例设置高度
        let h = compressedOption.height || (compressedOption.width ? compressedOption.width / (img.width / img.height) : '') || img.height

        // 生成canvas
        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')

        // 设置宽高并渲染图片
        canvas.width = w
        canvas.height = h
        ctx.drawImage(img, 0, 0, w, h)

        let base64 = canvas.toDataURL('image/jpeg', quality)
        // https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL

        // 回调函数返回base64的值
        callback(base64)
      }
    }

	// 图片转码处理
    const convertBase64UrlToFile = (urlData, filename) => {
      let arr = urlData.split(',')
      let mime = arr[0].match(/:(.*?);/)[1]

      let bstr = atob(arr[1])
      // https://www.runoob.com/jsref/met-win-atob.html
      let n = bstr.length

      let u8arr = new Uint8Array(n)
      // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
        // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt
      }

      // return new Blob([u8arr], { type: mime })
      // https://developer.mozilla.org/zh-CN/docs/Web/API/Blob

      return new File([u8arr], filename, { type: mime })
      // https://developer.mozilla.org/zh-CN/docs/Web/API/File
    }

	// 获取DOM并注册事件
    document.getElementById('inputeFile').addEventListener('change', (e) => {
      let file = e.target.files[0]

      photoCompress(
        file,
        {
          quality: 0.2,
          // width: 0,
          // height: 0
        },
        base64Codes => {
          let newFile = convertBase64UrlToFile(base64Codes, file.name)

          console.log(newFile)
        }
      )
    })

html标签

	<input id="inputeFile" type="file" accept="image/*"/>

convertBase64UrlToFile 函数中的转码,正常使用在上传接口中,iviewelement-ui的上传组件就用到了上述转码结果的格式。


三、 iview element-ui上传处理

iview源码、和element-ui源码 都有一个 before-upload 钩子。
before-upload:上传文件之前的钩子,参数为上传的文件,
若返回 false 或者返回 Promise 且被 reject,则停止上传。

这里我们需要在这个钩子里返回一个Promise

elementUI 上传组件源码 上传函数代码

upload(rawFile) {
 this.$refs.input.value = null;

 // 这个就是判断是否通过props传入上传前的钩子
 if (!this.beforeUpload) {
   return this.post(rawFile);
 }

 // 我们在这个钩子返回Promise
 const before = this.beforeUpload(rawFile);
 
 if (before && before.then) {
   before.then(processedFile => {
     const fileType = Object.prototype.toString.call(processedFile);
	
     // 上传返回压缩过后的图片文件,这里iview 只支持 File 格式,不支持 Blob 格式
     if (fileType === '[object File]' || fileType === '[object Blob]') {
       if (fileType === '[object Blob]') {
         processedFile = new File([processedFile], rawFile.name, {
           type: rawFile.type
         });
       }
       for (const p in rawFile) {
         if (rawFile.hasOwnProperty(p)) {
           processedFile[p] = rawFile[p];
         }
       }
       this.post(processedFile);
     } else {
       this.post(rawFile);
     }
   }, () => {
     this.onRemove(null, rawFile);
   });
 } else if (before !== false) {
   this.post(rawFile);
 } else {
   this.onRemove(null, rawFile);
 }
}

iviewelement-ui 源代码一样,只是 element-ui 更新后兼容Blob 格式,如果使用iviewupload 组件,只能 resolve(File)

下面就是我们在项目中要写的代码

<el-upload
  class="upload-demo"
  :before-update="beforeUpdate">
  <el-button size="small" type="primary">点击上传</el-button>
  <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
beforeUpdate (file, fileList) {
	return new Promise((resolve, reject) => {
		
		// 这个压缩函数,就是上面我们写的
		photoCompress(
	        file,
	        {
	          quality: 0.2,
	          // width: 0,
	          // height: 0
	        },
	        base64Codes => {
	          let newFile = convertBase64UrlToFile(base64Codes, file.name)
	
			  resolve(newFile)
	        }
	    )
	})
}

DEMO演示

http://rudyjoy.cn/compressImage

总结

压缩的方法总体理解起来也不麻烦,完整流程就是, 把原始图片 绘至 canvas。
canvas 使用 toDataURL 方法获取到压缩后的图片数据
最后转码返给 upload 组件使用

以上上传前压缩就写好了,如有疏漏或错误欢迎指正,谢谢。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值