目 录CONTENT

文章目录

使用canvas完成图片压缩

Hello!你好!我是村望~!
2022-08-09 / 0 评论 / 0 点赞 / 177 阅读 / 895 字
温馨提示:
我不想探寻任何东西的意义,我只享受当下思考的快乐~

开始总要说点啥

为了帮后端服务器分担一点压力啦!毕竟前端搞一些事情是在客户端搞,不行只能说客户电脑垃圾!

![img]image-1660128076694

目标

  • 1.按比例压缩
  • 2.可配置化参数(压缩的宽高比,和质量)
  • 3.异步的方式

思路

  • 1.将前端通过表单拿到File对象
  • 2.将File对象转为Img可以渲染的Base64
  • 3.我们去加载Image,拿到当前文件的原始宽高,去对比配置项的宽高,如果大于配置项的宽高则进行压缩,否则原图返回
  • 4.如果需要压缩的话,我们就去计算当前需要被压缩的比率,得到一个压缩后的等比例宽高,然后根据这个宽高生成canvas画布
  • 5.将我们的图片渲染到canvas上面,然后将canvas导出为一个DataURL,这个导出的图片就是按照我们宽高比压缩后的图片,也可以配置导出的质量参数

编码

;(function name(doc) {
	const compressUtil = {}
	function fileToBase64(file) {
		return new Promise((resolve, reject) => {
			let reader = new FileReader()
			reader.addEventListener('load', (e) => {
				resolve(e.target.result)
			})
			reader.readAsDataURL(file)
		})
	}
	//拿到base64渲染的iMG,用来获取原图的宽高
	function getNaturalDomForCalc(base64FileContext) {
		return new Promise((resolve, reject) => {
			const img = new Image()
			img.src = base64FileContext
			img.onload = function () {
				resolve(img)
			}
		})
	}
	//计算压缩比率
	function calcForCompressRate(img, compressConfig) {
		for (key in compressConfig) {
			this[key] = compressConfig[key]
		}
		return new Promise((resolve, reject) => {
			let rate,
				needToCompress = false,
				originHeight = img.naturalHeight,
				originWidth = img.naturalWidth
			if (originWidth > this.width) {
				needToCompress = true
				rate = originWidth / this.width
				originWidth = this.width
				//如果它的宽度被压缩了,那么高度肯定要按比例进行压缩
				originHeight = originHeight / rate
			}
			if (originHeight > this.height) {
				needToCompress = true
				rate = originHeight / this.height
				originHeight = this.height
				//如果它的宽度被压缩了,那么高度肯定要按比例进行压缩
				originWidth = originWidth / rate
			}
			const canvas = doc.createElement('canvas')
			canvas.width = originWidth
			canvas.height = originHeight
			canvas.style.display = 'none'
			doc.body.appendChild(canvas)
			const ctx = canvas.getContext('2d')
			ctx.clearRect(0, 0, originWidth, originHeight)
			ctx.drawImage(img, 0, 0, originWidth, originHeight)
			const compressedImg = canvas.toDataURL(this.fileType, this.quality)
			doc.body.removeChild(canvas)
			resolve(compressedImg)
		})
	}
	function dataURLtoBlob(base64) {
		let arr = base64.split(','),
			mime = arr[0].match(/:(.*?);/)[1],
			bstr = atob(arr[1]),
			n = bstr.length,
			u8arr = new Uint8Array(n)
		while (n--) {
			u8arr[n] = bstr.charCodeAt(n)
		}
		return new Blob([u8arr], { type: mime })
	}
	function compressImgToBase64(
		file,
		compressConfig = {
			width: 100,
			height: 100,
			quality: 0.5, //0-1
			fileType: 'image/jpeg',
		}
	) {
		let isRightConfig = true
		const RequiredConfigurationKeys = ['width', 'height', 'quality', 'fileType']
		for (let key in compressConfig) {
			RequiredConfigurationKeys.find((item) => item == key) ? '' : (isRightConfig = false)
		}
		if (!isRightConfig) {
			throw new Error(
				`Incorrect configuration. Please use a configuration in a format similar to this {width: 100,height: 100,quality: 0.5,fileType: 'image/jpeg',},Or, instead of passing the configuration, we'll use the default configuration\n 不正确的配置。请使用类似于{width: 100,height: 100,quality: 0.5,fileType: 'image/jpeg',}的格式配置,或者,我们将使用默认配置而不是传递的配置`
			)
		}
		return new Promise(async (resolve, reject) => {
			const base64Context = await fileToBase64(file)
			const img = await getNaturalDomForCalc(base64Context)
			const compressedImg = await calcForCompressRate(img, compressConfig)
			resolve(compressedImg)
		})
	}
	//向全局暴露唯一的工具
	compressUtil.compressImgToBase64 = compressImgToBase64
	compressUtil.base64toBlob = dataURLtoBlob
	window.compressUtil = compressUtil
})(document)

怎么用

<body>
    <input type="file" id='uploader'  multiple></input>
</body>

通过form表单 input file 去上传文件 ,监听表单的change事件,然后触发我们的工具函数,传入file对象和配置对象(可以不传,内部有默认值)

uploader.addEventListener('change',handleToUpload)
function handleToUpload(e){
 const files = e.target.files;
 for(let file of files){
 compressUtil.compressImgToBase64(file,{
			width: 100,
			height: 100,
			quality: 1, //0-1
			fileType: 'image/jpeg',
		}).then(res=>{
   console.log(res);
   console.log(compressUtil.base64toBlob(res));
 })
 }
}

测试 搞一张2m的图片来试一下

image-1660128102042

image-1660128111344

Good!

0

评论区