✨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转px
rpxToPx(rpx) {return (rpx / 750) * uni.getSystemInfoSync().windowWidth
},

⏳绘制函数

图片和单位的问题解决后,就要开始绘制海报了,这里需要根据ui效果图,去自行布局,本文档中只是作为一个例子。
在开发中发现canvas生成一倍图是比较模糊的,所以这里要定义一个倍数来放大canvas画布,使生成的图片更加的清晰,也就是代码中的canvasMultiplecanvasMultiple变量在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))// 插入logothis.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.tempFilePathuni.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: () => {}})
}

⏳至此生成海报并可以保存至相册的函数都已经完成,组装至一起既可以完成需求

完整代码

<template><u-popup :show="displayPoster" mode="center"  @close="close" :overlayOpacity="0.8" :closeOnClickOverlay="true" :safeAreaInsetBottom="false"><view :class="posterImage ? 'poster' : 'poster-hidden'"><canvas v-if="posterImage === ''" canvas-id="canvas" class="poster-canvas" :style="{width:'1180rpx',height: '1952rpx'}"></canvas><template v-if="posterImage"><image class="poster-image" :src="posterImage"></image><view class="save-btn"><u-button :customStyle="saveButtonStyle" type="primary" text="保存海报" @click.stop="savePoster"></u-button></view></template><view class="close-icon" v-if="posterImage" @click.stop = "close" ><image class="icon" :src="imgUrl+'close-white.png'"></image></view></view></u-popup>
</template><script>
export default {name: 'PosterDialog',props: {displayPoster: {type: Boolean,required: true}},data() {return {imgUrl: `${_SWF_CONFIG.TEMPLATE_URL}${_SWF_CONFIG.TEMPLATE_PATH}/images/`,canvasMultiple: 2,saveButtonStyle: {background: '#0C1C2B',border: '1px solid #0C1C2B',width: '280rpx',height: '88rpx',fontSize: '32rpx',fontWeight: '500'},posterImage: '',nickName: ''}},watch: {displayPoster: {handler(newValue) {console.log('newValue', newValue)const { displayName } = uni.getStorageSync('userInfo')this.nickName = displayNameconsole.log('nickName', this.nickName)if (newValue) {this.creatCanvas()}},immediate: true}},methods: {async creatCanvas() {if (this.posterImage) return// const that = this// 创建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))// 插入logothis.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.tempFilePathuni.hideLoading()// this.canvas.draw()},fail: (e) => {uni.showToast({title: '海报生成失败',icon: 'none'})this.close()console.log('eeee', e)}}, this)}, 500)})},// rpx转pxrpxToPx(rpx) {return (rpx / 750) * wx.getSystemInfoSync().windowWidth},// 下载图片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')}})})},close() {this.$emit('close')},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: () => {}})}}
}
</script><style scoped lang="scss">
.poster{width: 590rpx;height: 976rpx;position: relative;
}
.close-icon{width: 54rpx;height: 54rpx;position: absolute;display: flex;justify-content: center;align-items: center;top: 0;right: 0;background: rgba(43,47,54,.5);.icon{width: 35rpx;height: 35rpx;}
}
.poster-hidden{width: 0rpx;height: 0rpx;overflow: hidden;
}
.save-btn{position: absolute;left: calc(50% - 140rpx);bottom: -130rpx;
}
.poster-canvas{transform: translateY(99999999999999rpx);
}
.poster-image{width: 590rpx;height: 976rpx;
}
</style>

⏳看到上方代码,先是利用canvas生成图片,将图片用image标签展示出来,cavans元素移除屏幕外,这里可能有疑问为什么要这么做?直接用canvas元素来展示图片不好吗?为什么要用canvas生成的图片来显示呢?

⏳这么做的原因其实是因为canvas在抖音小程序,微信小程序部分真机中没有动画过渡,当弹窗关闭时比较突兀,当然如果需求中没有动画过渡的要求,就不需要多这一步。

小程序uniapp利用canvas生成海报并可以保存至相册相关推荐

  1. 微信小程序-运用painter插件生成海报分享朋友圈--比canvas好用

    微信小程序-运用painter插件生成海报–比canvas好用 先放插件地址:https://github.com/Kujiale-Mobile/Painter 还有个可视化把海报生成代码的地址:ht ...

  2. 小程序发布之后无法生成海报问题

    CRMEB商城 小程序发布之后无法生成海报问题 1.小程序需要正式发布后,才能生成产品二维码 2.检测小程序后台,检测下载域名是否配置:"downloadFile合法域名" 3.检 ...

  3. 微信小程序利用canvas生成海报-------图片为网络图片

    根据我们老总的业务需求,迫不得已,我做了这个canvas绘制的海报,感觉基本上可以解决现在海报所遇到的大部分问题了,献给那些没有做过的小伙伴们,话不多说,先上我做的效果 上代码 <style&g ...

  4. 小程序开发-利用canvas实现保存二维码海报到本机

    场景及需求 在小程序开发过程中,经常需要实现保存某个页面为带小程序码的二维码海报图片到本地,然后用于分享或者发朋友圈等操作. 主要技术点及小程序相关api 技术注意事项 小程序的canvas与H5 c ...

  5. 微信小程序分享朋友圈生成海报

    微信小程序实现分享到朋友圈 分享朋友圈现在大家的通用做法就是通过Canvas生成一张图片后进行保存,然后自行转发朋友圈.最近项目有这个需求, 于是就记录一下.(老规矩,我的博客复制粘贴就好使) 如果想 ...

  6. 小程序中 使用canvas 生成推广图片——wepy框架

    现在小程序不能直接分享到朋友圈,所以另辟蹊径的有了生成 '推广图' 让用户分享到朋友圈的方式就出来了.使用canvas 进行绘图的时候 主要用了 ctx.drawImage() API进行绘画,但是c ...

  7. 在微信小程序中实现生成海报图并保存到相册

    效果图镇楼: 技术依赖: 弹窗 (vant-weapp 提供的 van-popup 组件) 海报图 (wx-canvas-2d 工具) 弹窗组件的使用方式可以点击上面链接查看,本篇主要讲解海报图绘制方 ...

  8. 小程序中使用canvas绘制海报

    最近项目需求使用canvas绘制朋友圈可分享的海报,中间遇到很多问题,于是上网搜索,完美解决后,在此总结一下. 先来看一下效果图,点击按钮生成带二维码的图片. 1.关于canvas画布的宽度和高度 w ...

  9. 微信小程序使用Painter组件生成海报

    文档地址 我是直接下载github源码放到项目组件中 {"usingComponents": {"painter": "../../component ...

最新文章

  1. 国内首个面向工业级实战的点云处理课程
  2. rundll32.exe文件详解
  3. golang微服务框架对比_微服务里程碑,Golang与Spring Cloud Alibaba完美结合
  4. JVM 对象状态判断01
  5. Angular使用中的编码tips(持续更)
  6. 0009:err:module:__wine_process_init failed to load xxx
  7. 机器人炒饭小块头一一_小块头机器人炒饭:全智能流程,炒饭芬芳独具
  8. linux查分自动备份tar,linux 下tar的增量备份
  9. test title
  10. SQL SERVER 数据库概括
  11. matlab多项式运算开方,matlab多项式运算【技术材料】
  12. 八种抽样技术的科学指南
  13. 推荐一个直接用于项目开发的PID库!很好用,很稳定
  14. 微型计算机由中央处理器,zy1.微型计算机中央处理器是由()组成的。
  15. 【Linux中sudo命令】
  16. canvas教程8-小球连线之碰壁则返
  17. 你知道什么叫“无差别沟通”吗
  18. MIS软件工程师的面试问题与方法
  19. 解决系统中没有ASPNET用户的烦恼
  20. JavaScript 获得对象的N种方法 [转]

热门文章

  1. 如何在linux上配置网桥
  2. html中aside怎么调整位置,HTML5中的aside标签怎么用?HTML5aside侧边栏的具体使用方法你知道吗?...
  3. 相机稳定性测试软件,四种方法,确保运动中的相机提供最佳视频稳定性
  4. PS三种切图方法+Cutterman(安装教程、基本使用)
  5. quarts之Cron表达式示例
  6. 手机里有哪些不想卸载且好用的APP?
  7. Unity(lua) Text添加空格导致换行问题
  8. Leaf(美团分布式ID生成服务)核心代码分析
  9. 【OpenCV 例程200篇】45. 图像的灰度直方图(cv2.calcHist)
  10. who is killer