微信小程序绘制海报并保存相册
tip:代码中使用的是uni的api 如果使用原生微信小程序开发,可以把uni更换成wx使用
文章目录
- 微信小程序绘制海报并保存相册
- 前言
- 一、分析需求
- 二、准备数据
- 三、编码开始
- html部分
- 解析:
- js部分
- 1、准备好数据后开始绘制
- 解释:
- 2、保存图片
- 解析:
- 总结
前言
本片文章主要是把我工作中实际用到,可以整合出来的功能,做一个总结和讲解。
1、如何使用canvas
2、canvas绘制后如何生成图片
3、将图片保存到相册
4、难点
:如何解决canvas层级高于position定位层级问题,如何适配不同屏幕大小比例
一、分析需求
两种方案:
- 进入页面先绘制canvas,点击按钮后再生成图片并保存相册
- 进入页面先绘制canvas,并生成图片,点击按钮直接保存图片到相册
我这边使用的是第一种方式,看实际需求。(其实没多大区别)
二、准备数据
在开始绘制canvas之前首先要,分析页面中用到了哪些内容:
- 背景图片
- 二维码图片
- 关于海报的一些描述性文案
注意:
1、由于这些数据可能不是页面写死的内容,是根据api返回的数据,所以需要在绘制canvas之前就先准备好从api返回的数据。
2、需要考虑同步问题
三、编码开始
先看下页面图片样式
html部分
<canvas :style="{height:pageHeight,width: _width +'px'}" canvas-id="mycanvas" />
<cover-view @tap="saveImg"><cover-image src="btn_img.png"></cover-image>
</cover-view>
解析:
1、首先需要准备一个canvas用于绘制页面内容的载体,id是唯一标识
2、需要一个按钮用于保存图片,但是发现即使用绝对定位调整层级还是不能将按钮显示到canvas上层,所以借助于官方提供的覆盖原生组件的方法。cover-view
和cover-image
。
js部分
这里只说代码重点部分。
页面中用到的变量可以自行修改,至于变量的初始值都可以是空字符串
1、准备好数据后开始绘制
onReady() {// 为了兼容不同机型页面大小,所以需要先获取到页面宽高this.getSysInfo()
},
getSysInfo() {/*获取手机宽高*/let that = thislet imgUrl = this.imageUrllet qrcodeUrl = this.codeUrluni.getSystemInfo({success(res) {console.log('屏幕宽度', res)that._width = res.windowWidththat._heigth = res.windowHeight// 获取图片信息生成canvas// 因为这里用的网络图片所以需要先获取本地网络图地址that.getImginfo([imgUrl, qrcodeUrl], 0);}})
},
getImginfo(urlArr, _type) {let that = this;uni.getImageInfo({src: urlArr[_type],success: function(res) {//res.path是网络图片的本地地址if (_type === 0) { //that.localImageUrl = res.paththat.getImginfo(urlArr, 1)} else {//二维码that.localCodeUrl = res.path// 创建canvas图片that.createNewImg();}},fail: function(res) {//失败回调console.log('错误', _type, res)}});
},
createNewImg() {let that = this;let ctx = uni.createCanvasContext('mycanvas');// 绘制背景ctx.drawImage(this.localImageUrl, 0, 0, this._width, this._heigth - 44 - this.statusBarHeight);// 绘制二维码区域ctx.lineJoin = "round";ctx.lineWidth = 12;ctx.setFillStyle('#FFFFFF')ctx.setStrokeStyle('#FFFFFF')// 二维码区域y坐标const yPosition = this._heigth - 44 - this.statusBarHeight - this.remSize(98) - 100ctx.strokeRect(this.remSize(24), yPosition, this.remSize(326), this.remSize(98));ctx.fillRect(this.remSize(24), yPosition, this.remSize(326), this.remSize(98));// 绘制二维码const yPosition2 = yPosition + 4ctx.drawImage(this.localCodeUrl, this.remSize(28), yPosition2, this.remSize(90), this.remSize(90));//二维码区域文字let title1 = this.tips.title1;let title2 = this.tips.title2;let title3 = this.tips.title3;// 文字一ctx.setFontSize(this.remSize(14));ctx.setFillStyle('#333333');ctx.fillText(title1, this.remSize(128), yPosition + this.remSize(30));// 文字二三ctx.setFillStyle('#B8B8B8');ctx.setFontSize(this.remSize(12));ctx.fillText(title2, this.remSize(128), yPosition + this.remSize(62));ctx.fillText(title3, this.remSize(128), yPosition + this.remSize(85));// 绘制ctx.draw();//将生成好的图片保存到本地uni.canvasToTempFilePath({canvasId: 'mycanvas',success: (res)=> {that.loadImagePath = res.tempFilePath},fail: (res)=> {console.log(res);}});
},
// 缩放比例
let scalePage = uni.getSystemInfoSync().windowWidth / 375remSize(num) {return num * scalePage
},
解释:
1、uni.createCanvasContext
创建canvas上下文,用于操作绘制具体图片和文字
2、ctx.drawImage
用于绘制图片
3、ctx.setFillStyle
用于绘制填充色
4、ctx.setStrokeStyle
用于绘制边框颜色
5、因为canvas不能绘制圆角实心矩形,所以取巧的方式,就是用圆角矩形和实心矩形覆盖的方式,效果见上图。
6、ctx.strokeRect
绘制矩形空心
7、ctx.fillRect
绘制矩形实心
6、ctx.setFontSize
ctx.setFillStyle
ctx.fillText
绘制文字大小,颜色,位置
7、ctx.draw()
把所有的上下文内容,绘制到canvas上面
特别说明:
- remSize方法,根据设计稿去设置图片大小和文案的位置比例,我这边是根据375像素的宽度计算比例。
- 这些api具体使用方法,可以参考官方文档,这里就不一一列举了。
2、保存图片
//点击保存到相册
saveImg() {uni.saveImageToPhotosAlbum({filePath: this.loadImagePath,success(res) {uni.showToast({title: '已保存到相册',icon: 'success',duration: 3000})}})
},
解析:
1、因为保存按钮是固定定位,并且按钮并非canvas绘制内容,所以保存图片的时候并不会有按钮。
2、需要注意的是,保存相册是需要相册保存权限的,这个可以看文档自己去设置。
总结
上面的说的覆盖问题,还可以是先使用canvas把直接生成图片,然后在页面上直接显示生成好的图片。
如有问题,欢迎指正修改。