最近做了一个问卷类的小程序,其中的结果页想让用户进行朋友圈分享转发,网上搜索资料,得出解决思路,用 canvas 将页面绘制生成图片,然后保存到手机相册,最终效果如下:

在这里我只写页面里关于 canvas 生成图片并进行保存这个流程的相关代码,并且会在我踩过的坑那里进行具体的讲述。废话不多说直接上干货


wxml

<!-- 调用canvas图片绘制方法 按钮 -->
<view class="share" bindtap="share"><image class="share-img" src="/images/icon-share.png" mode="widthFix" lazy-load="true"></image>分享助力
</view>
<!-- 黑色透明层 -->
<view hidden="{{hiddenImg}}" class="mask"></view>
<!-- 调用保存图片到手机相册方法 按钮 -->
<view class="share-btn" hidden="{{hiddenImg}}" bindtap="save">保存到相册</view>
<!-- canvas -->
<view class='canvas-box'><canvas canvas-id='share' style='width:100vw;height:100vh;' hidden='{{canvasHidden}}'></canvas>
</view>
<!-- canvas 绘制完成后显示的图片 -->
<image class="shareimg" src="{{shareImgPath}}" style="height:{{winHeight}}" mode="widthFix" hidden="{{hiddenImg}}"></image>

wxss

.share {width: 356rpx;height: 80rpx;text-align: center;line-height: 80rpx;color: #e73322;font-size: 32rpx;border-radius: 37rpx;background: #fff;margin: 70rpx auto 0;
}.share-img {width: 31rpx;
}.canvas-box {position: fixed;top: 99999px;left: 0;width: 100%;
}.shareimg {position: fixed;top: 0;left: 0;width: 100%;height: 100%;
}.mask {position: fixed;z-index: 1;background: rgba(0, 0, 0, .5);top: 0;left: 0;bottom: 0;right: 0;
}.share-btn {position: fixed;width: 356rpx;bottom: 50rpx;left: 197rpx;height: 80rpx;text-align: center;line-height: 80rpx;color: #e73322;font-size: 32rpx;border-radius: 37rpx;background: #fff;z-index: 999;
}

js

1. 设置 data 相关默认值

  • canvasHidden: true 设置使 canvas 隐藏,因为 canvas 是原生组件,拥有最高层级,如果不隐藏,会影响页面正常使用
  • hiddenImg: true 设置使黑色遮罩、保存按钮和显示生成后的图片隐藏
data: {canvasHidden: true, wxappName: "来「 老字号文化影响力 」测试你的知识等级",hiddenImg: true
},

2. 在 onLoad 方法中准备需要用到的参数

这里需要注意一点我踩过的坑,

  • 由于小程序的canvas 不能使用网络图片,所以缓存中的头像不能直接用,需要使用wx.downloadFile方法将头像路径存储为临时路径,以供 canvas 使用,由于之前不知道这个,所有折腾半天,画出来的图片就是没有头像
  • 这里获取设备宽度、高度以及设备像素比也非常重要,用于最后显示图片的大小以及canvas画图过程中的宽高显示
onLoad: function (o) {var that = this;//读取缓存,获取微信头像和昵称wx.getStorage({key: 'user',success: function (res) {var nickName = res.data.nickName,avatarUrl = res.data.avatarUrl;that.setData({nickName: nickName,})// 由于canvas不能使用网络图片,所以此处进行头像临时路径存储wx.downloadFile({url: avatarUrl,success: (res) => {that.setData({avatarUrl: res.tempFilePath,})},});}})//获取用户设备信息,屏幕宽度wx.getSystemInfo({success: res => {that.setData({screenWidth: res.screenWidth,winHeight: res.windowHeight,ratio: res.pixelRatio})}})},

3. 编写 canvas 绘制方法

  • 第一步显示画板,配置需要显示的元素

这里需要注意 unit = that.data.screenWidth / 375 用于使用像素值进行绘制后进行手机不同机型大小的适配,context = wx.createCanvasContext('share') 用于指定要绘制的 canvas,其余的参数都是我项目中需要用到的,各位童鞋可以根据自己的需求进行配置

//定义的保存图片方法
share: function () {wx.showLoading({title: '图片生成中...',})var that = this;//设置画板显示,才能开始绘图that.setData({canvasHidden: false})var res = that.data.res.result;var resImg;switch (res) {case 1:resImg = '/images/sdj.png';break;case 2:resImg = '/images/js.png';break;case 3:resImg = '/images/jr.png';break;case 4:resImg = '/images/gs.png';break;case 5:resImg = '/images/xc.png';break;}var unit = that.data.screenWidth / 375;var ratio = that.data.ratio;var screenWidth = that.data.screenWidth;var winHeight = that.data.winHeight;var bg = "/images/bg.png"var avatarUrl = that.data.avatarUrl;var bgleavel = "/images/bg-leavel.png";var qrcode = "/images/qrcode.jpg";var nickName = that.data.nickName;var context = wx.createCanvasContext('share');var idnum = that.data.res.id;var num = idnum.toString();var length = num.length;var left;switch (length) {case 2:left = 375 - 208 - length * 26break;case 3:left = 375 - 208 - length * 24break;case 4:left = 375 - 208 - length * 20break;case 5:left = 375 - 208 - length * 19break;default:left = 375 - 208 - length * 18break;}var wxappName = that.data.wxappName;
  • 第二步开始绘制将所需元素逐一绘制到画板上

这里我有踩到的坑,就是图片绘制完成后,在手机上显示非常模糊,多番查找折腾后,发现以下几个地方设置好之后就OK了
width: screenWidth 设定指定的画布区域的宽度
height: winHeight 设定指定的画布区域的高度
destWidth: ratio * screenWidth 设定输出图片宽度
destHeight: ratio * winHeight 设定输出图片高度
quality: 1, 设定图片质量

destWidth 和 destHeight 需要设置为width 和height 的 2倍或以上才能让图片清晰,而现在的智能手机设备像素比一般都在2以上,所以这里直接用 ratio 来进行设置

图片绘制完成且临时路径生成之后,打开隐藏的遮罩层和保存按钮以及供用户浏览的生成之后的图片

   // 绘制红色背景context.drawImage(bg, 0, 0, that.data.screenWidth, winHeight)// 绘制头像var avatarurl_width = unit * 75; //绘制的头像宽度var avatarurl_heigth = unit * 75; //绘制的头像高度var avatarurl_x = unit * 150; //绘制的头像在画布上的位置var avatarurl_y = unit * 35; //绘制的头像在画布上的位置context.save();//先画个圆   前两个参数确定了圆心 (x,y) 坐标  第三个参数是圆的半径  四参数是绘图方向  默认是false,即顺时针context.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2, false);context.clip(); //画好了圆 剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 这也是我们要save上下文的原因context.drawImage(avatarUrl, avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth); // 将头像放到绘制好的圆中context.restore(); //恢复之前保存的绘图上下文状态 还可以继续绘制.// 绘制昵称context.setFontSize(14)context.setFillStyle('#fff')context.setTextAlign('center')context.fillText(nickName, unit * 187, unit * 135)// 绘制知识等级背景图context.drawImage(bgleavel, unit * 110, unit * 165, unit * 312 / 2, unit * 307 / 2)context.drawImage(resImg, unit * 160, unit * 180, unit * 110 / 2, unit * 238 / 2)// 绘制第几位宣传者context.setFontSize(16)context.setFillStyle('#fff')context.setTextAlign('right')context.fillText('你是第', left * unit, unit * 382)context.setFontSize(24)context.setFillStyle('#fff')context.setTextAlign('center')context.fillText(num, unit * (left + length * 12), unit * 382)context.setFontSize(16)context.setFillStyle('#fff')context.setTextAlign('left')context.fillText('位老字号文化传播大使', unit * (left + length * 24), unit * 382)// 绘制二维码context.drawImage(qrcode, unit * 138, unit * 410, unit * 204 / 2, unit * 204 / 2)// 绘制二维码下部文字context.setFontSize(12)context.setFillStyle("#fff")context.setTextAlign("center")context.fillText("长按识别小程序", unit * 187.5, unit * 540)context.fillText(wxappName, unit * 187.5, unit * 560)//把画板内容绘制成图片,并回调 画板图片路径context.draw(false, function () {wx.canvasToTempFilePath({x: 0,y: 0,width: screenWidth,height: winHeight,destWidth: ratio * screenWidth,destHeight: ratio * winHeight,canvasId: 'share',quality: 1,success: function (res) {that.setData({shareImgPath: res.tempFilePath,hiddenImg: false,pathRes: res})if (!res.tempFilePath) {wx.showModal({title: '提示',content: '图片绘制中,请稍后重试',showCancel: false})}wx.hideLoading()}})});
},

4. 编写保存到手机相册方法

这里没什么好说的,就是调用微信提供的API 进行图片保存,成功或者失败之后,进行相应提示并将一开始在data中设置的需要默认隐藏的元素进行隐藏,然后就OK了,打开手机相册就可以看到完成的图片进行朋友圈分享了。

save: function () {var that = this;var res = that.data.pathRes;wx.saveImageToPhotosAlbum({filePath: res.tempFilePath,//保存成功失败之后,都要隐藏画板,否则影响界面显示。success: (res) => {wx.showToast({title: '保存成功',icon: 'none',duration: 1500,mask: false,success: function () {that.setData({canvasHidden: true,hiddenImg: true})}});},fail: (err) => {wx.showToast({title: '保存失败',icon: 'none',duration: 1500,mask: false,success: function () {that.setData({canvasHidden: true,hiddenImg: true})}});}})
}

最后写一下用到的API吧,常用的就不写了主要写一下我自己平时不怎么经常用到的

  1. wx.downloadFile 用于将网络图片生成临时路径,这里也有一个坑,需要在小程序公众平台将腾讯的 wx.qlogo.cn 这个域名设置为合法域名,否则会报错,在之后的绘制中图片尽量用本地路径
  2. wx.createCanvasContext 其中在画布中进行绘制的时候如果有什么不明白的,可以到 w3cschool 看看,链接是直接跳转到 canvas 绘图这一节的
  3. wx.canvasToTempFilePath 将画板内容绘制成图片的方法,需要注意上面提到的影响手机图片清晰度的参数,其中所有参数具体配置以及含义,可以直接到 官方文档 查看
  4. wx.saveImageToPhotosAlbum 保存图片到本地的API,这个没有难点,不多说了

整篇文章看着代码多,其实用到的不常见的API也就这几个,注意一下文章中我踩过的那几个坑,相信你可以开发出一个完美的带小程序码的用于分享到朋友圈的图片了。

========================================================================================================================

2020年4月16日 补充

1、字体加粗
通过文字多次绘制可以模拟字体的加粗
2、标题文字过长加省略号
通过 measureText 方法获取标题长度,与自己实际展示标题长度做判断,循环进行截取,直到满足条件为止

var titleWidth = context.measureText(title).width;
context.fontSize = 16 * unit;
if(titleWidth > (320*unit)){while (titleWidth > (320*unit)) {title = title.substring(0, (title.length - 1));titleWidth = context.measureText(title).width;// console.log(title,titleWidth,i,title.length,(title.length - 1))}title = title + '...';
}

微信小程序踩坑记录 ------- canvas 生成带小程序码的微信朋友圈分享图相关推荐

  1. 纯Java实现微信朋友圈分享图

    纯Java实现微信朋友圈分享图 1.实现分享图的效果 2.开发环境 2.1 JDK * oracle's jdk 1.8以上 2.2 字体 * 若选择了微软雅黑字体又是代码部署到Linux,则需要安装 ...

  2. 记录配置微信外链跳转小程序踩坑(H5跳转小程序)

    1.已有的小程序里面选择云开发,准备工作:下载官方demo 1.1新建云函数(参考:静态网站 H5 跳小程序 | 微信开放文档) 这个地方和官方操作一致,但是要特别注意如果设置了下图的话,云函数名称必 ...

  3. 微信小游戏踩坑记录(二)

    2019独角兽企业重金招聘Python工程师标准>>> 微信视频组件 这次是关于视频组件的,creator的视频组件在小游戏中是没有用的,只能使用小游戏自带的组件.使用小游戏Vide ...

  4. node 对接微信支付的踩坑记录(服务端)

    因项目需要,对接了微信支付,微信支付对于网页来说没有什么工作量,申请了商户号后,直接将收款码放到网页上就可以,但是小程序需要调起微信支付直接付款,于是认真翻阅了官网要针对小程序做微信支付的对接. 准备 ...

  5. 微信小程序 点击生成朋友圈分享图

    A:wxml(一定要加上image标签,如果你没有加的话,那么即使图片生成了,在页面上也是不会显示的,问过大神之后我才知道我之前一直没弄出来是因为我没加image标签) 1 <view hidd ...

  6. js 通过canvas生成带二维码的海报图

    前言 h5移动端生成海报图,可长按图片保存或发送给朋友,或长按识别二维码.两种场景:第一种是生成项目分享海报图,通过背景图和地址生成的二维码合成一张海报图:第二种是通过页面生成商品海报图,页面有产品介 ...

  7. 微信开放标签踩坑记录

    先上微信官方文档 微信文档 以下要注意的点: 微信版本要求为:7.0.12及以上. 系统版本要求为:iOS 10.3及以上.Android 5.0及以上. 微信sdk版本需要在1.6.0以上,版本过低 ...

  8. 微信小程序朋友圈分享图片生成方案实现

    在小程序界里,生成图片分享到朋友圈这个功能,是如此得光芒耀眼,以至于各个小程序都趋之若鹜地前来跪倒在她的石榴裙下.不幸的是,微信爸爸并没有提供给我们很好很便捷的相关工具:恰恰相反,屏幕截屏的功能被残忍 ...

  9. tabbar角标 小程序_【沃行课堂】恭喜你遇到“坑”,小程序踩坑指南

    上周我们的开发小哥哥带领我们一起领略了开发中遇到的各种问题,以及基于SaaS模式的平台技术架构及实现.本周我们换个方向,由高级开发工程师秋哥带领大家共同探讨下小程序开发中踩过的坑.秋哥会从公司的几个小 ...

最新文章

  1. windows 注册表讲解
  2. MFC:怎么将程序窗口最小化到系统托盘
  3. 数学之路(2)-数据分析-R基础(4)
  4. Linux环境下C语言模拟内存负载测试
  5. 增量式pid调节方式有何优点_增量式PID的“假抗饱和”性
  6. 十四、去年写的Numpy使用方法梳理,2020年5月13日整理
  7. C#多线程之旅(七)——终止线程
  8. java sftp mget_总结三种Shell脚本编程中避免SFTP输入密码的方法
  9. 11.2.0.2的SPM的一个bug
  10. 拼多多服务端实习生笔试-滑动窗口2018/4/3
  11. 关于静态事件 static event 的二三事
  12. office visio 替代_5款替代微软Visio的开源免费软件(转)
  13. Yate架构分析概要
  14. Dwz 国产框架 JUI 分页组件下拉菜单bug解决方案
  15. 2018-9-30-C#-从零开始写-SharpDx-应用-画三角
  16. 监听springboot进程,如果关闭就重启
  17. 二维码生成插件qrious(纯JS)
  18. 云应用设计模式(三)
  19. 准备开发一个智能硬件,得先看这篇文章!
  20. 阿里研究院启动2018年度淘宝村辅助认证活动

热门文章

  1. Java语言程序设计 例题5.4(英里和公里的转化)
  2. 真人语音朗读软件_影视解说视频配音,抖音配音,微课配音,实用免费配音软件,文本朗读,一键文字转语音,媲美真人的配音软件...
  3. Win电脑截图黑屏解决办法
  4. 数据转移高效方法(oracle)
  5. C++57个入门知识点_17 类的访问权限及C语言模拟类的封装(类的私有权限突破方法:编译期进行权限检查,运行期通过指针修改类的私有成员变量;利用函数指针对结构体中成员变量进行修改;CPU大小尾排列)
  6. (素材源码)猫猫学IOS(十七)UI之纯代码自定义Cell实现新浪微博UI
  7. SDFRayMarching
  8. IE和Firefox兼容性
  9. kafka请求全流程(二)—— 请求的接收以及分发
  10. 千万不要说联通的网络不好……