✨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. Java堆内存分配与回收策略
  2. 10分钟完成一个业务流程的发布
  3. c语言编程学生管理,c语言编程,关于学生管理的程序(急急急)
  4. 什么方式可以通过影子系统传播恶意代码_将恶意代码隐藏在图像中:揭秘恶意软件使用的隐写术...
  5. html页面怎么引用通用的头部,html 如何引入一个公共的头部和底部
  6. 毕设项目 - 基于SSM的企业公寓宿舍后勤管理系统(含源码+论文)
  7. c语言读取三菱plc数据,三菱plc怎么读取程序_电脑读取三菱PLC数据简单方法
  8. oppor829t如何刷机_科普OPPO R1 R829T的线刷教程及最简单的三星手机刷机教程
  9. pdf阅读器与迅捷pdf编辑器的使用方法
  10. 1873年2月1日 麦克斯韦《电磁通论》出版
  11. 14届数独-真题标准数独-Day 5-20220120
  12. PVE解决VM is locked问题
  13. Java多线程(7):JUC(下)
  14. 2020年携程校招开发方向第一题
  15. android webview静态方法,在android webview中加载静态页面
  16. 聊聊IT外包公司(外包公司的运作模式和赚钱之道)
  17. 抖音快手YY西瓜斗鱼花椒虎牙等直播平台实时录制
  18. ABBYY FineReader 14
  19. NORDIC Thingy:52 蓝牙 BLE 服务 SoC 程序调用流程分析之八, 网盘分享 PPT
  20. 不重复随机数的产生 (C++)

热门文章

  1. Android自动手绘,Android实现手绘功能
  2. html5中英文间自动空格,WordPress 文章中英文数字间自动添加空格 代码
  3. 在url中取ip或者键值对、手机号脱敏、电话号脱敏、身份证脱敏、银行卡号脱敏、身份证校验
  4. iconfont 图标转为字体_iconfont字体图标的使用
  5. win7如何连接域控服务器,win7系统创建域控制器的操作方法
  6. androidframework层面试题,有java基础学android
  7. 忠义俱全:忠和资本刘国忠与用户分享财富之道
  8. 软件需求工程 高校教学平台 软件需求规格说明书 part 3 (重点!!!)
  9. DefaultSerializer requires a Serializable payload but received an object of type [reggie.common.R]
  10. CS225[02] CA1 知识库