✨uniapp实现生成海报并保存至相册组件,u-popup可以根据自己所使用的组件进行替换
这里主要讲的是JS部分,css和元素相关的就不展开赘述了,下方先给大伙看看效果图,图的下方有代码讲解,最下方有完整代码,如各位大神发现问题后请友好的交流勿喷。
⏳示例图
⏳ 图片引用
想要用cavans生成海报,首先要解决的是,将图片素材引入至canvas画布中,小程序的canvas没有办法直接使用网络图片,所以首先要把网络中的图片获取到,并已文件的格式存入内存中,利用uniapp的api简单的封装了一个获取图片的函数
// 下载图片urlToFile(url) { return new Promise((resolve) => { uni.getImageInfo({ src: url, success(res) { resolve(res.path) }, fail(res) { console.log('fail -> res', res) uni.showToast({ title: '网络异常', duration: 2000, icon: 'none' }) this.$emit('close') } }) })},
⏳转换rpx
拿到图片后,还有个问题要处理,那就是尺寸,在小程序中用的rpx为样式的单位。但是在canvas中却没有rpx的单位,所以我们要处理一下px转为rpx,这样就能解决不同分辨率中,样式大小不同的问题。一样的一个简单的转换函数
// rpx转pxrpxToPx(rpx) { return (rpx / 750) * uni.getSystemInfoSync().windowWidth},
⏳绘制函数
图片和单位的问题解决后,就要开始绘制海报了,这里需要根据ui效果图,去自行布局,本文档中只是作为一个例子。
在开发中发现canvas生成一倍图是比较模糊的,所以这里要定义一个倍数来放大canvas画布,使生成的图片更加的清晰,也就是代码中的canvasMultiple
,canvasMultiple
变量在data
中有定义,如果有些变量看着不明白,可以先看最下方的完整代码
async creatCanvas() { if (this.posterImage) return // 创建canvas对象 uni.showLoading({ title: '生成专属海报' }) this.canvas = uni.createCanvasContext('canvas', this) // 这里是我自己的方法下载图片 // canvas中的插入的图片不能是网络地址只能是下载到本地的 const qrCode = await this.urlToFile(`${this.imgUrl}poster-code.png`) const imgBg = await this.urlToFile(`${this.imgUrl}poster-bg.png`) const logoIcon = await this.urlToFile(`${this.imgUrl}poster-logo.png`) const fontImage = await this.urlToFile(`${this.imgUrl}poster-font.png`) const { canvasMultiple, rpxToPx } = this // 插入背景图 第2 3 4 5参数单位是px的所以我们要做适配 rpx转换为px 可以自定义方法 也可以使用uniapp中的方法 this.canvas.drawImage(imgBg, 0, 0, rpxToPx(590 * canvasMultiple), rpxToPx(976 * canvasMultiple)) // 将二维码插入到canvas中 this.canvas.drawImage(qrCode, rpxToPx(460 * canvasMultiple), rpxToPx(780 * canvasMultiple), rpxToPx(100 * canvasMultiple), rpxToPx(100 * canvasMultiple)) // 插入logo this.canvas.drawImage(logoIcon, rpxToPx(74 * canvasMultiple), rpxToPx(114 * canvasMultiple), rpxToPx(84 * canvasMultiple), rpxToPx(64 * canvasMultiple)) this.canvas.drawImage(fontImage, rpxToPx(80 * canvasMultiple), rpxToPx(334 * canvasMultiple), rpxToPx(351 * canvasMultiple), rpxToPx(53 * canvasMultiple)) this.canvas.fillStyle = '#ffffff' this.canvas.strokeStyle = '#ffffff' // this.canvas.font = `bold ${rpxToPx(40)}px` this.canvas.font = `normal normal 500 40px 微软雅黑` this.canvas.setFontSize(rpxToPx(40 * canvasMultiple)) this.canvas.fillText(this.nickName, rpxToPx(80 * canvasMultiple), rpxToPx(274 * canvasMultiple)) this.canvas.font = `normal normal 600 26px 微软雅黑` this.canvas.setFontSize(rpxToPx(26 * canvasMultiple)) this.canvas.fillText('立即扫码', rpxToPx(80 * canvasMultiple), rpxToPx(850 * canvasMultiple)) this.canvas.fillStyle = 'rgba(255, 255, 255, 0.43)' this.canvas.strokeStyle = 'rgba(255, 255, 255, 0.43)' this.canvas.font = `normal normal 400 26px 微软雅黑` this.canvas.setFontSize(rpxToPx(26 * canvasMultiple)) this.canvas.fillText('生成的热乎的海报', rpxToPx(80 * canvasMultiple), rpxToPx(900 * canvasMultiple)) // 成功之后 this.canvas.draw(true, () => { setTimeout(() => { // 将canvas转换成图片 uni.canvasToTempFilePath({ x: 0, y: 0, canvasId: 'canvas', fileType: 'png', quality: 1, success: (success) => { console.log('success', success) this.posterImage = success.tempFilePath uni.hideLoading() // this.canvas.draw() }, fail: (e) => { uni.showToast({ title: '海报生成失败', icon: 'none' }) this.close() console.log('eeee', e) } }, this) }, 500) })},
⏳保存至相册
小程序中提供了将图片保存至相册的能力,所以这里只需要把刚刚canvas绘制的海报图片,利用uniapp的saveImageToPhotosAlbum
存至相册中就可以了。
savePoster() { console.log('savePoster', this.posterImage) uni.saveImageToPhotosAlbum({ filePath: this.posterImage, success: () => { // uni.hideLoading(); uni.showToast({ title: '保存成功', icon: 'none' }) this.close() }, fail: () => { uni.hideLoading() this.$toast({ title: '相册功能未授权,无法保存' }) }, complete: () => { } })}
⏳至此生成海报并可以保存至相册的函数都已经完成,组装至一起既可以完成需求
完整代码
⏳看到上方代码,先是利用canvas生成图片,将图片用image
标签展示出来,cavans元素移除屏幕外,这里可能有疑问为什么要这么做?直接用canvas元素来展示图片不好吗?为什么要用canvas生成的图片来显示呢?
⏳这么做的原因其实是因为canvas在抖音小程序,微信小程序部分真机中没有动画过渡,当弹窗关闭时比较突兀,当然如果需求中没有动画过渡的要求,就不需要多这一步。
🎇感谢大家阅读,如有帮助或问题欢迎给赞👍和讨论
来源地址:https://blog.csdn.net/qq2468103252/article/details/130572956