微信小程序图片前端压缩(canvas)

将需要压缩的图片绘制在canvas,然后利用微信提供的canvasToTempFilePath()方法保存成一个图片,保存时可以根据所需指定生成图片的质量。

通过canvas配合这个接口,可以实现两种图片的压缩:1.声明好图片高度/宽度临界值,压缩图片的宽高;2.不改变图片的宽高,只改变图片的质量;

首先页面需要声明一个canvas画布:其中cWidth和cHeight分别是渲染的图片高度和宽度,根据上传的图片信息获取;-9999px是为了使画布偏离屏幕;

<canvas 
    canvas-id="canvas"
    class="my-canvas"
	:style="{width:cWidth+'px',height:cHeight+'px'}">
</canvas>
.canvas {
    position: absolute;
    left: -9999px;
    top: -9999px
}

1.通过修改图片的宽高来压缩图片

通过修改宽高来压缩图片的原理是获取图片的宽高后(res.width/res.height),判断是否满足自己的最高宽/高度要求,如果不满足,则根据比例缩小,直到获取到满足要求的宽高,将其渲染到页面上,这里加一个setTimeout是因为canvas绘制需要一定的时间,需要等canvas绘制完成后将其通过canvasToTempFilePath方法导出;

wx.canvasToTempFilePath(Object object, Object this) | 微信开放文档

通过这种方法有两个弊端:

1.无法完全确定图片的高度,而且在一定情况下两张图片宽高差距比较大(宽高2049px和宽高2047px的两张图片),解决办法:

        1.1 减小ratio的初始值,同时减小增长间隔:初始值1.2,增长间隔0.2(ratio += 0.2);

        1.2 完全固定图片的高度或者宽度,等比例调整至固定的大小,弊端就是小图片会被拉长;

2.无法实时的判断图片是否渲染完毕(目前我是没找到方法,欢迎指导),尤其是渲染的图片宽高特别大的时候会特别耗时,所设置的延迟可能会导致导出的图片不全/拉伸等情况,解决办法:

        2.1 这种修改图片的宽高方法,可以找到一个最大宽高所需渲染的时间,比这个宽高小的图片在当前时间内一定会渲染完成;如果是第二种方法,修改图片的质量,则需要预留一个比较充足的时间,但是特别大的图片可能还会有一样的问题。

async imgCompress(tempFilePaths, index) {
	let _this = this
	return new Promise((resolve, reject) => {
		wx.getImageInfo({
			src: tempFilePaths,
			success: function(res) {
				let ratio = 2;
				let canvasWidth = res.width
				let canvasHeight = res.height
				while (canvasWidth > 1024 || canvasHeight > 1024) {
					canvasWidth = Math.trunc(res.width / ratio)
					canvasHeight = Math.trunc(res.height / ratio)
					ratio++;
				}
				_this.cWidth = canvasWidth
				_this.cHeight = canvasHeight
				let ctx = wx.createCanvasContext('canvas')
                ctx.clearRect(0, 0, canvasWidth, canvasHeight);
				ctx.drawImage(res.path, 0, 0, canvasWidth, canvasHeight)
				ctx.draw(false, _this.timer = setTimeout(function() {
					wx.canvasToTempFilePath({
						canvasId: 'canvas',
						destWidth: canvasWidth, // 输出的图片的宽度
						destHeight: canvasHeight, // 输出的图片的高度
						fileType: 'png', // 图片输出格式
						quality: 1, // 图片质量 0-1
						success: function(res) {
                            clearTimeout(_this.timer)
							resolve(res.tempFilePath);
						},
						fail: function(res) {
                            clearTimeout(_this.timer)
							reject(err.errMsg)
						}
					})
				}, 600)) //留一定的时间绘制canvas
			},
			fail: function(res) {
				reject(err.errMsg)
			},
		})
	})
},

2.通过修改图片导出的质量来压缩图片

看过第一种方法的代码,也应该知道这种方法怎么实现了,绘制图片时以原始的宽高来绘制,只是在导出图片的时候,通过修改quality(0-1)的大小来实现压缩图片;

通过这种方法的弊端:

1. quality目前只支持jpg图片,和微信提供的wx.compressImage()方法一样,这就要求导出的图片类型必须是jpg图片;

2. 和第一种方法一样的问题,无法确切的知道图片渲染完成的时间........

async imgCompress(tempFilePaths, index) {
	let _this = this
	return new Promise((resolve, reject) => {
		wx.getImageInfo({
			src: tempFilePaths,
			success: function(res) {
				let ratio = 2;
				let canvasWidth = res.width
				let canvasHeight = res.height
				_this.cWidth = canvasWidth
				_this.cHeight = canvasHeight
				let ctx = wx.createCanvasContext('canvas')
				ctx.clearRect(0, 0, canvasWidth, canvasHeight);
				ctx.drawImage(res.path, 0, 0, canvasWidth, canvasHeight)
				ctx.draw(false, _this.timer = setTimeout(function() {
					wx.canvasToTempFilePath({
						canvasId: 'canvas',
						destWidth: canvasWidth, // 输出的图片的宽度
						destHeight: canvasHeight, // 输出的图片的高度
						fileType: 'jpg', // 图片输出格式
						quality: 0.2, // 图片质量,0-1
						success: function(res) {
							clearTimeout(_this.timer)
							resolve(res.tempFilePath);
						},
						fail: function(res) {
							clearTimeout(_this.timer)
							reject(err.errMsg)
						}
					})
				}, 600)) //留一定的时间绘制canvas
			},
			fail: function(res) {
				reject(err.errMsg)
			},
		})
	})
},

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值