小程序开发笔记《七》使用canvas绘制带二维码海报并预览保存到相册

小程序生成带二维码的海报效果预览: 项目需求: 需要根据用户信息生成用户个人二维码,后台提供海报素材,将用户二维码画在海报上,并可预览海报,长按保存海报,方便用户分享或者发朋友圈。 涉及到的相关API: wx.getImageInfo()----获取图片信息 wx.getSystemInfo()----获取系统信息,包括屏幕宽高,设备型号,设备像素比等 wx.canvasToTempFilePath()----把当前画布指定区域的内容导出生成指定大小的图片 wx.saveImageToPhotosAlbum()----保存图片到系统相册。 canvas渲染相关api 注意事项: 小程序的canvas基本实现了H5的canvas方法,包括往画布画图片,导成图片等,因此可直接使用小程序的canvas相关api。 小程序绘制二维码在网上找的插件 小程序canvas与image组件默认宽度300px、高度225px 小程序canvas相关的api中单位为px,并非rpx,因此在业务实现过程中可根据需要处理适配 小程序canvas对跨域图片不支持,需要先将图片缓存到本地(网络图片上线的时候还需要配置downloadFile域名),本地图片不需要调用getImageInfo()方法进行本地缓存 实现过程: 1.首先根据个人信息绘制二维码,绘制二维码使用的插件weapp-qrcode,具体实现过程可参考上一篇文章小程序开发笔记《五》生成二维码,然后将绘制的二维码画布导出图片并拿到图片本地临时链接,方便后续在海报上画二维码的时候调用。 2.获取设备屏幕信息,计算出海报预览时图片的宽高,因为image组件有默认宽度300px、高度225px,如果不计算的话图片以固定尺寸呈现可能会变形。 3.绘制canvas,在定义好的canvas上先绘制海报底图,这个例子底图与绘制的画布尺寸相同,然后将用户二维码绘制到海报的右下角。 4.设置海报的导出尺寸,将canvas内容导出生成指定尺寸的图片。注意:wx.canvasToTempFilePath必须要在draw的回调中执行,否则会生成失败,官方文档有说明,需要将生成的图片路径存下来,方便长按保存的时候直接拿图片路径进行操作 5.长按将图片保存到系统相册 踩坑记录: 1.在二维码中间绘制logo图片:如果使用的是网络地址的图片, 需要先使用 wx.getImageInfo 去获取图片信息; 2.利用 x,y 可以画出有 padding 感觉的二维码图片; 3.直接在callback中调用 wx.canvasToTempFilePath 在部分安卓机上转出来的二维码图片异常(不完整),二维码扫不出来, 需要设置计时器; 实现代码: index.wxml: index.js: import drawQrcode from '../../utils/weapp.qrcode.js' Page({ data: { shareUrl: "https://www.baidu.com/", shareQrcodeImage: "", shareQrcodeWidth: 200, shareQrcodeHeight: 200, haibaoBgUrl: "https://upload-images.jianshu.io/upload_images/13079544-96b37469be760003.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240", haiBaoWidth: 750, //海报默认宽 haiBaoHeight: 1334, //海报默认高 haiBaoShowHeight: 0, qrcode_x: 600, //二维码据左上角x轴距离 qrcode_y: 980, //二维码据左上角Y轴距离 display: 'none', user_id: 1 }, onLoad: function() { var that = this; //生成专属二维码 that.createQrCode(); //获取屏幕信息 wx.getSystemInfo({ success(res) { that.setData({ windowWidth: res.windowWidth, windowHeight: res.windowHeight }) } }); }, hideModal: function() { this.setData({ display: "none", position: "" }) }, /**生成200*200的二维码,上下左右各留20px的白边 */ createQrCode: function() { var this_ = this; drawQrcode({ width: 160, height: 160, x: 20, y: 20, canvasId: 'myQrcode', // ctx: wx.createCanvasContext('myQrcode'), typeNumber: 10, text: this_.data.shareUrl + this_.data.user_id,//二维码的链接携带个人信息,根据实际业余需求做修改 image: { imageResource: '../../images/mini_app_logo.png', dx: 70, dy: 70, dWidth: 60, dHeight: 60 }, callback(e) { // 导出图片 setTimeout(() => { wx.canvasToTempFilePath({ x: 0, y: 0, width: this_.data.shareQrcodeWidth, height: this_.data.shareQrcodeHeight, destWidth: this_.data.shareQrcodeWidth, destHeight: this_.data.shareQrcodeHeight, canvasId: 'myQrcode', success(res) { console.log('二维码的临时url:', res.tempFilePath) let tempFilePath = res.tempFilePath this_.setData({ shareQrcodeImage: tempFilePath }) } }) },100) } }) }, createHB: function(e) { var that = this; that.setData({ display: 'block' }); if (that.data.shareImgSrc) { //已画过就不再画 return; } wx.showLoading({ title: '生成中', }) var imgUrl = that.data.haibaoBgUrl; var codeX = that.data.qrcode_x; var codeY = that.data.qrcode_y; wx.getImageInfo({ src: imgUrl, success(res) { console.log("res.path:" + res.path) const ctx = wx.createCanvasContext('myCanvas'); //二维码 var qrcodeImg = that.data.shareQrcodeImage; // 海报显示最大宽高 var screenW = that.data.windowWidth - 30; var screenH = that.data.windowHeight - 30; var bgW = res.width; // 海报实际宽 var bgH = res.height; // 海报实际宽 var haiBaoShowWidth_ = screenW; var haiBaoShowHeight_ = screenH if (bgW < screenW) { haiBaoShowWidth_ = bgW; } // 按宽度等比缩放的高 var sjht = bgH * haiBaoShowWidth_ / bgW; if (sjht < screenH) { haiBaoShowHeight_ = sjht; } that.setData({ haiBaoWidth: res.width, haiBaoHeight: res.height, haiBaoShowWidth: haiBaoShowWidth_, haiBaoShowHeight: haiBaoShowHeight_ }) //画海报底图 ctx.drawImage(res.path, 0, 0, that.data.haiBaoWidth, that.data.haiBaoHeight); //画海报二维码,海报宽高200*200,坐标减去20是方便二维码的白边显示,可去掉 ctx.drawImage(qrcodeImg, codeX - 20, codeY - 20, 200, 200) //canvasToTempFilePath必须要在draw的回调中执行,否则会生成失败,官方文档有说明 ctx.draw(false, setTimeout(function() { wx.canvasToTempFilePath({ x: 0, y: 0, canvasId: 'myCanvas', success: function(res) { wx.hideLoading(); that.setData({ shareImgSrc: res.tempFilePath }) }, fail: function(res) { wx.hideLoading(); wx.showToast({ title: '生成失败', icon: "none" }) } }) }, 200)); } }) console.log("imgUrl:" + imgUrl); }, /**长按保存到相册*/ savePic: function() { var that = this; getAuto(function() { wx.saveImageToPhotosAlbum({ filePath: that.data.shareImgSrc, success: function(res) { wx.showToast({ title: '保存成功', icon: 'success', duration: 2000 }) }, fail: function(res) { wx.showToast({ title: '保存失败', icon: 'none', duration: 2000 }) } }) }) } }) /**获取保存相册授权*/ function getAuto(_success) { wx.getSetting({ success(res) { if (!res.authSetting['scope.writePhotosAlbum']) { wx.authorize({ scope: 'scope.writePhotosAlbum', success() { _success(); } }) } else { _success(); } } }) } index.wxss: /**index.wxss**/ .main { margin-top: 200px; } .modal-mask { width: 100%; height: 100%; position: fixed; top: 0; left: 0; background: #000; z-index: 1001; -moz-opacity: 0.7; opacity: 0.70; filter: alpha(opacity=70); overflow: hidden; } .image-modal .modal-main { width: 100%; height: 100%; position: fixed; top: 0; left: 0; padding: 15px; box-sizing: border-box; background-color: transparent; z-index: 1002; } .myQrcode,.canvas-box { height: 100%; width: 100%; position: fixed; left: 0; top: 999999rpx; } 代码已上传,可直接下载 原文作者技术博客:https://www.jianshu.com/u/ac4daaeecdfe

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):